Skip to content

Commit ceb96ff

Browse files
committed
Optional edge hints with fixed fold behavior.
1 parent 2adb633 commit ceb96ff

1 file changed

Lines changed: 124 additions & 44 deletions

File tree

  • trustfall_core/src/interpreter/hints

trustfall_core/src/interpreter/hints/mod.rs

Lines changed: 124 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use std::collections::BTreeMap;
44
use std::fmt::Debug;
55
use std::sync::Arc;
66

7-
use crate::ir::{Argument, ContextField, FieldRef, IRQuery, IRVertex, Operation};
7+
use crate::ir::{
8+
Argument, ContextField, FieldRef, IREdge, IRFold, IRQuery, IRVertex, Operation, Recursive,
9+
};
810
use crate::{
911
interpreter::basic_adapter::{ContextIterator, ContextOutcomeIterator},
1012
ir::{Eid, FieldValue, IRQueryComponent, Vid},
@@ -102,7 +104,7 @@ pub trait VertexInfo {
102104
// optional, recursed, or folded edge;
103105
// recursed because recursion always starts at depth 0
104106
// TODO: What happens if the same edge exists more than once in a given scope?
105-
// fn optional_edge(&self, edge_name: &str) -> Option<EdgeInfo>;
107+
fn optional_edge(&self, edge_name: &str) -> Option<EdgeInfo>;
106108
}
107109

108110
#[non_exhaustive]
@@ -177,6 +179,40 @@ pub struct LocalQueryInfo {
177179
current_vertex: Vid,
178180
}
179181

182+
impl LocalQueryInfo {
183+
fn make_non_folded_edge_info(&self, edge: &IREdge) -> EdgeInfo {
184+
let neighboring_info = NeighboringQueryInfo {
185+
query: self.query.clone(),
186+
starting_vertex: self.current_vertex,
187+
neighbor_vertex: edge.to_vid,
188+
neighbor_path: vec![edge.eid],
189+
};
190+
EdgeInfo {
191+
eid: edge.eid,
192+
optional: edge.optional,
193+
recursive: edge.recursive.clone(),
194+
folded: false,
195+
destination: neighboring_info,
196+
}
197+
}
198+
199+
fn make_folded_edge_info(&self, fold: &IRFold) -> EdgeInfo {
200+
let neighboring_info = NeighboringQueryInfo {
201+
query: self.query.clone(),
202+
starting_vertex: self.current_vertex,
203+
neighbor_vertex: fold.to_vid,
204+
neighbor_path: vec![fold.eid],
205+
};
206+
EdgeInfo {
207+
eid: fold.eid,
208+
optional: true,
209+
recursive: None,
210+
folded: true,
211+
destination: neighboring_info,
212+
}
213+
}
214+
}
215+
180216
impl VertexInfo for LocalQueryInfo {
181217
#[inline]
182218
fn current_vertex(&self) -> &IRVertex {
@@ -202,6 +238,7 @@ impl VertexInfo for LocalQueryInfo {
202238
return Some(DynamicallyResolvedValue {
203239
query: self.query.clone(),
204240
vid: vertex.vid,
241+
resolve_on_component: self.query.query.indexed_query.vids[&vertex.vid].clone(),
205242
context_field: context_field.clone(),
206243
is_multiple: false,
207244
});
@@ -210,6 +247,7 @@ impl VertexInfo for LocalQueryInfo {
210247
return Some(DynamicallyResolvedValue {
211248
query: self.query.clone(),
212249
vid: vertex.vid,
250+
resolve_on_component: self.query.query.indexed_query.vids[&vertex.vid].clone(),
213251
context_field: context_field.clone(),
214252
is_multiple: true,
215253
});
@@ -236,23 +274,27 @@ impl VertexInfo for LocalQueryInfo {
236274
&& edge.recursive.is_none()
237275
&& edge.edge_name.as_ref() == edge_name
238276
});
239-
if let Some(matching_edge) = first_matching_edge {
240-
let neighboring_info = NeighboringQueryInfo {
241-
query: self.query.clone(),
242-
starting_vertex: self.current_vertex,
243-
neighbor_vertex: matching_edge.to_vid,
244-
neighbor_path: vec![matching_edge.eid],
245-
};
246-
Some(EdgeInfo {
247-
eid: matching_edge.eid,
248-
optional: false,
249-
recursive: None,
250-
folded: false,
251-
destination: neighboring_info,
277+
first_matching_edge.map(|edge| self.make_non_folded_edge_info(edge.as_ref()))
278+
}
279+
280+
fn optional_edge(&self, edge_name: &str) -> Option<EdgeInfo> {
281+
// TODO: What happens if the same edge exists more than once in a given scope?
282+
let component = self.current_component();
283+
let current_vertex = self.current_vertex();
284+
let first_matching_edge = component.edges.values().find(|edge| {
285+
edge.from_vid == current_vertex.vid && edge.edge_name.as_ref() == edge_name
286+
});
287+
first_matching_edge
288+
.map(|edge| self.make_non_folded_edge_info(edge.as_ref()))
289+
.or_else(|| {
290+
component
291+
.folds
292+
.values()
293+
.find(|fold| {
294+
fold.from_vid == current_vertex.vid && fold.edge_name.as_ref() == edge_name
295+
})
296+
.map(|fold| self.make_folded_edge_info(fold.as_ref()))
252297
})
253-
} else {
254-
None
255-
}
256298
}
257299
}
258300

@@ -261,7 +303,7 @@ impl VertexInfo for LocalQueryInfo {
261303
pub struct EdgeInfo {
262304
eid: Eid,
263305
optional: bool,
264-
recursive: Option<usize>, // TODO: perhaps a better inner type, to represent "no-limit" too?
306+
recursive: Option<Recursive>,
265307
folded: bool,
266308
destination: NeighboringQueryInfo,
267309
}
@@ -281,6 +323,44 @@ pub struct NeighboringQueryInfo {
281323
neighbor_path: Vec<Eid>,
282324
}
283325

326+
impl NeighboringQueryInfo {
327+
fn make_non_folded_edge_info(&self, edge: &IREdge) -> EdgeInfo {
328+
let mut neighbor_path = self.neighbor_path.clone();
329+
neighbor_path.push(edge.eid);
330+
let neighboring_info = NeighboringQueryInfo {
331+
query: self.query.clone(),
332+
starting_vertex: self.starting_vertex,
333+
neighbor_vertex: edge.to_vid,
334+
neighbor_path,
335+
};
336+
EdgeInfo {
337+
eid: edge.eid,
338+
optional: edge.optional,
339+
recursive: edge.recursive.clone(),
340+
folded: false,
341+
destination: neighboring_info,
342+
}
343+
}
344+
345+
fn make_folded_edge_info(&self, fold: &IRFold) -> EdgeInfo {
346+
let mut neighbor_path = self.neighbor_path.clone();
347+
neighbor_path.push(fold.eid);
348+
let neighboring_info = NeighboringQueryInfo {
349+
query: self.query.clone(),
350+
starting_vertex: self.starting_vertex,
351+
neighbor_vertex: fold.to_vid,
352+
neighbor_path,
353+
};
354+
EdgeInfo {
355+
eid: fold.eid,
356+
optional: true,
357+
recursive: None,
358+
folded: true,
359+
destination: neighboring_info,
360+
}
361+
}
362+
}
363+
284364
impl VertexInfo for NeighboringQueryInfo {
285365
#[inline]
286366
fn current_vertex(&self) -> &IRVertex {
@@ -330,6 +410,7 @@ impl VertexInfo for NeighboringQueryInfo {
330410
query: self.query.clone(),
331411
vid: vertex.vid,
332412
context_field: context_field.clone(),
413+
resolve_on_component: self.query.query.indexed_query.vids[&self.starting_vertex].clone(),
333414
is_multiple: false,
334415
});
335416
}
@@ -340,6 +421,7 @@ impl VertexInfo for NeighboringQueryInfo {
340421
query: self.query.clone(),
341422
vid: vertex.vid,
342423
context_field: context_field.clone(),
424+
resolve_on_component: self.query.query.indexed_query.vids[&self.starting_vertex].clone(),
343425
is_multiple: true,
344426
});
345427
}
@@ -365,37 +447,35 @@ impl VertexInfo for NeighboringQueryInfo {
365447
&& edge.recursive.is_none()
366448
&& edge.edge_name.as_ref() == edge_name
367449
});
368-
if let Some(matching_edge) = first_matching_edge {
369-
let mut neighbor_path = self.neighbor_path.clone();
370-
neighbor_path.push(matching_edge.eid);
371-
let neighboring_info = NeighboringQueryInfo {
372-
query: self.query.clone(),
373-
starting_vertex: self.starting_vertex,
374-
neighbor_vertex: matching_edge.to_vid,
375-
neighbor_path,
376-
};
377-
Some(EdgeInfo {
378-
eid: matching_edge.eid,
379-
optional: false,
380-
recursive: None,
381-
folded: false,
382-
destination: neighboring_info,
383-
})
384-
} else {
385-
None
386-
}
450+
first_matching_edge.map(|edge| self.make_non_folded_edge_info(edge.as_ref()))
387451
}
388452

389-
// fn optional_edge(&self, edge_name: &str) -> Option<EdgeInfo> {
390-
// // similar concerns as above in `required_edge()`
391-
// todo!()
392-
// }
453+
fn optional_edge(&self, edge_name: &str) -> Option<EdgeInfo> {
454+
// TODO: What happens if the same edge exists more than once in a given scope?
455+
let component = self.current_component();
456+
let current_vertex = self.current_vertex();
457+
let first_matching_edge = component.edges.values().find(|edge| {
458+
edge.from_vid == current_vertex.vid && edge.edge_name.as_ref() == edge_name
459+
});
460+
first_matching_edge
461+
.map(|edge| self.make_non_folded_edge_info(edge.as_ref()))
462+
.or_else(|| {
463+
component
464+
.folds
465+
.values()
466+
.find(|fold| {
467+
fold.from_vid == current_vertex.vid && fold.edge_name.as_ref() == edge_name
468+
})
469+
.map(|fold| self.make_folded_edge_info(fold.as_ref()))
470+
})
471+
}
393472
}
394473

395474
#[non_exhaustive]
396475
pub struct DynamicallyResolvedValue {
397476
query: QueryInfo,
398477
vid: Vid,
478+
resolve_on_component: Arc<IRQueryComponent>,
399479
context_field: ContextField,
400480
is_multiple: bool,
401481
}
@@ -410,11 +490,11 @@ impl DynamicallyResolvedValue {
410490
adapter: &mut AdapterT,
411491
contexts: ContextIterator<'vertex, VertexT>,
412492
) -> ContextOutcomeIterator<'vertex, VertexT, CandidateValue<FieldValue>> {
413-
let component = &self.query.query.indexed_query.vids[&self.vid].clone();
493+
// let component = &self.query.query.indexed_query.vids[&self.vid].clone();
414494
let iterator = compute_context_field_with_separate_value(
415495
adapter,
416496
&mut self.query,
417-
component,
497+
&self.resolve_on_component,
418498
&self.context_field,
419499
contexts,
420500
);

0 commit comments

Comments
 (0)