1use crate::store::{
18 AdjacencyReadMemory, GraphExecutionRead, GraphExecutionWrite, PrunedNodeScan,
19 PrunedRelationshipScan, ScanControl, SourceScanCandidateRow, SourceScanCandidateVisit,
20 SourceScanReadLimits,
21};
22use crate::QueryMemoryLease;
23use hawdb_core::error::Result;
24use hawdb_core::schema::Catalog;
25use hawdb_core::{LabelId, RelTypeId};
26use hawdb_plan_cypher::NodeProjectionAccess;
27use hawdb_storage::store::{GraphScanControl, GraphStore};
28use hawdb_storage::{
29 adjacency::AdjacencyDirection,
30 mutation::{GraphMutation, MutationLimits, MutationSummary, NodeSetAssignment, PropertyFilter},
31 NodeId, NodeRecord, ProjectedNodeRecord, RelId, RelRecord,
32};
33use std::collections::BTreeSet;
34
35fn to_store_control(control: ScanControl) -> GraphScanControl {
36 match control {
37 ScanControl::Continue => GraphScanControl::Continue,
38 ScanControl::Stop => GraphScanControl::Stop,
39 }
40}
41
42fn to_execution_control(control: GraphScanControl) -> ScanControl {
43 match control {
44 GraphScanControl::Continue => ScanControl::Continue,
45 GraphScanControl::Stop => ScanControl::Stop,
46 }
47}
48
49fn adapt_node_consumer(
50 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
51 visit: impl FnOnce(&mut dyn FnMut(NodeRecord) -> GraphScanControl) -> Result<GraphScanControl>,
52) -> Result<ScanControl> {
53 let mut consumer_error = None;
54 let control = visit(&mut |node| match consumer(node) {
55 Ok(control) => to_store_control(control),
56 Err(error) => {
57 consumer_error = Some(error);
58 GraphScanControl::Stop
59 }
60 })?;
61 match consumer_error {
62 Some(error) => Err(error),
63 None => Ok(to_execution_control(control)),
64 }
65}
66
67impl hawdb_storage::read_view::GraphReadAllocation for QueryMemoryLease {
68 fn bytes(&self) -> usize {
69 self.bytes()
70 }
71 fn grow(&mut self, bytes: usize) -> hawdb_core::Result<()> {
72 QueryMemoryLease::grow(self, bytes)
73 }
74}
75
76impl GraphExecutionRead for GraphStore {
77 fn file_descriptor_context(&self) -> Option<hawdb_storage::file_descriptors::FileOpenContext> {
78 GraphStore::file_descriptor_context(self)
79 }
80
81 fn is_out_of_core(&self) -> bool {
82 GraphStore::is_out_of_core(self)
83 }
84
85 fn projected_node_owned_admitted(
86 &self,
87 id: NodeId,
88 required_properties: &BTreeSet<String>,
89 admit: &mut dyn FnMut(usize) -> Result<()>,
90 ) -> Result<Option<ProjectedNodeRecord>> {
91 GraphStore::projected_node_owned_admitted(self, id, required_properties, admit)
92 }
93
94 fn node_owned(&self, id: NodeId) -> Result<Option<NodeRecord>> {
95 GraphStore::node_owned(self, id)
96 }
97
98 fn node_with_allocation(
99 &self,
100 id: NodeId,
101 label_ids: Option<&[LabelId]>,
102 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
103 ) -> Result<hawdb_storage::read_view::AdmittedNodeRead> {
104 GraphStore::node_with_allocation(self, id, label_ids, admit)
105 }
106
107 fn relationship_with_allocation(
108 &self,
109 id: RelId,
110 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
111 ) -> Result<hawdb_storage::read_view::AdmittedRelationshipRead> {
112 GraphStore::relationship_with_allocation(self, id, admit)
113 }
114
115 fn scan_nodes_borrowed<'a>(
116 &'a self,
117 label_id: Option<LabelId>,
118 ) -> Box<dyn Iterator<Item = &'a NodeRecord> + 'a> {
119 Box::new(GraphStore::scan_nodes(self, label_id))
120 }
121
122 fn scan_indexed_nodes_borrowed<'a>(
123 &'a self,
124 label_id: LabelId,
125 property: &str,
126 value: &hawdb_core::Value,
127 ) -> Option<Box<dyn Iterator<Item = &'a NodeRecord> + 'a>> {
128 Some(Box::new(GraphStore::seek_nodes_by_property(
129 self, label_id, property, value,
130 )))
131 }
132
133 fn node_count_for_label(&self, label_id: Option<LabelId>) -> usize {
134 GraphStore::node_count_for_label(self, label_id)
135 }
136
137 fn visit_indexed_projected_nodes_by_property_admitted(
138 &self,
139 label_id: LabelId,
140 property: &str,
141 values: &[hawdb_core::Value],
142 properties: &BTreeSet<String>,
143 admit: &mut hawdb_storage::read_view::GraphReadAllocator<'_>,
144 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
145 ) -> Result<Option<ScanControl>> {
146 GraphStore::visit_indexed_projected_nodes_by_property_admitted(
147 self,
148 label_id,
149 property,
150 values,
151 properties,
152 admit,
153 &mut |node| consumer(node).map(to_store_control),
154 )
155 .map(|control| control.map(to_execution_control))
156 }
157
158 fn relationship_count_for_type(&self, rel_type: Option<RelTypeId>) -> usize {
159 GraphStore::relationship_count_for_type(self, rel_type)
160 }
161
162 fn visit_nodes_owned(
163 &self,
164 label_id: Option<LabelId>,
165 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
166 ) -> Result<ScanControl> {
167 GraphStore::try_visit_nodes_owned(self, label_id, |node| {
168 consumer(node).map(to_store_control)
169 })
170 .map(to_execution_control)
171 }
172
173 fn visit_relationships_with_allocation(
174 &self,
175 rel_type: Option<RelTypeId>,
176 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
177 consumer: &mut dyn FnMut(
178 hawdb_storage::read_view::AdmittedRelationshipRecord,
179 ) -> Result<ScanControl>,
180 ) -> Result<ScanControl> {
181 GraphStore::visit_relationships_with_allocation(self, rel_type, admit, &mut |record| {
182 consumer(record).map(to_store_control)
183 })
184 .map(to_execution_control)
185 }
186
187 fn visit_nodes_with_allocation(
188 &self,
189 label_id: Option<LabelId>,
190 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
191 consumer: &mut dyn FnMut(
192 hawdb_storage::read_view::AdmittedNodeRecord,
193 ) -> Result<ScanControl>,
194 ) -> Result<ScanControl> {
195 GraphStore::visit_nodes_with_allocation(self, label_id, admit, &mut |node| {
196 consumer(node).map(to_store_control)
197 })
198 .map(to_execution_control)
199 }
200
201 fn visit_nodes_by_access_with_allocation(
202 &self,
203 label_id: LabelId,
204 access: &NodeProjectionAccess,
205 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
206 consumer: &mut dyn FnMut(
207 hawdb_storage::read_view::AdmittedNodeRecord,
208 ) -> Result<ScanControl>,
209 ) -> Result<ScanControl> {
210 GraphStore::visit_nodes_by_access_with_allocation(
211 self,
212 label_id,
213 access,
214 admit,
215 &mut |node| consumer(node).map(to_store_control),
216 )
217 .map(to_execution_control)
218 }
219
220 fn visit_projected_nodes_admitted(
221 &self,
222 label_id: Option<LabelId>,
223 properties: &BTreeSet<String>,
224 admit: &mut hawdb_storage::read_view::GraphReadAllocator<'_>,
225 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
226 ) -> Result<ScanControl> {
227 GraphStore::visit_projected_nodes_admitted(self, label_id, properties, admit, &mut |node| {
228 consumer(node).map(to_store_control)
229 })
230 .map(to_execution_control)
231 }
232
233 fn visit_projected_nodes_with_allocation(
234 &self,
235 label_id: Option<LabelId>,
236 properties: &BTreeSet<String>,
237 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
238 consumer: &mut dyn FnMut(
239 hawdb_storage::read_view::AdmittedProjectedNode,
240 ) -> Result<ScanControl>,
241 ) -> Result<ScanControl> {
242 GraphStore::visit_projected_nodes_with_allocation(
243 self,
244 label_id,
245 properties,
246 admit,
247 &mut |node| consumer(node).map(to_store_control),
248 )
249 .map(to_execution_control)
250 }
251
252 fn visit_projected_nodes_by_access_admitted(
253 &self,
254 label_id: LabelId,
255 access: &NodeProjectionAccess,
256 properties: &BTreeSet<String>,
257 admit: &mut hawdb_storage::read_view::GraphReadAllocator<'_>,
258 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
259 ) -> Result<ScanControl> {
260 GraphStore::visit_projected_nodes_by_access_admitted(
261 self,
262 label_id,
263 access,
264 properties,
265 admit,
266 &mut |node| consumer(node).map(to_store_control),
267 )
268 .map(to_execution_control)
269 }
270
271 fn visit_projected_nodes_by_property_admitted(
272 &self,
273 label_id: LabelId,
274 property: &str,
275 values: &[hawdb_core::Value],
276 properties: &BTreeSet<String>,
277 admit: &mut hawdb_storage::read_view::GraphReadAllocator<'_>,
278 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
279 ) -> Result<ScanControl> {
280 GraphStore::visit_projected_nodes_by_property_admitted(
281 self,
282 label_id,
283 property,
284 values,
285 properties,
286 admit,
287 &mut |node| consumer(node).map(to_store_control),
288 )
289 .map(to_execution_control)
290 }
291
292 fn visit_projected_nodes_owned(
293 &self,
294 label_id: Option<LabelId>,
295 required_properties: &BTreeSet<String>,
296 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
297 ) -> Result<ScanControl> {
298 let mut consumer_error = None;
299 let control =
300 GraphStore::visit_projected_nodes_owned(self, label_id, required_properties, |node| {
301 match consumer(node) {
302 Ok(control) => to_store_control(control),
303 Err(error) => {
304 consumer_error = Some(error);
305 GraphScanControl::Stop
306 }
307 }
308 })?;
309 match consumer_error {
310 Some(error) => Err(error),
311 None => Ok(to_execution_control(control)),
312 }
313 }
314
315 fn visit_projected_nodes_by_access_owned(
316 &self,
317 label_id: LabelId,
318 access: &NodeProjectionAccess,
319 required_properties: &BTreeSet<String>,
320 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
321 ) -> Result<ScanControl> {
322 let mut consumer_error = None;
323 let control = GraphStore::visit_projected_nodes_by_access_owned(
324 self,
325 label_id,
326 access,
327 required_properties,
328 |node| match consumer(node) {
329 Ok(control) => to_store_control(control),
330 Err(error) => {
331 consumer_error = Some(error);
332 GraphScanControl::Stop
333 }
334 },
335 )?;
336 match consumer_error {
337 Some(error) => Err(error),
338 None => Ok(to_execution_control(control)),
339 }
340 }
341
342 fn visit_projected_nodes_by_property_owned(
343 &self,
344 label_id: LabelId,
345 property: &str,
346 values: &[hawdb_core::Value],
347 required_properties: &BTreeSet<String>,
348 consumer: &mut dyn FnMut(ProjectedNodeRecord) -> Result<ScanControl>,
349 ) -> Result<ScanControl> {
350 let mut consumer_error = None;
351 let control = GraphStore::visit_projected_nodes_by_property_owned(
352 self,
353 label_id,
354 property,
355 values,
356 required_properties,
357 |node| match consumer(node) {
358 Ok(control) => to_store_control(control),
359 Err(error) => {
360 consumer_error = Some(error);
361 GraphScanControl::Stop
362 }
363 },
364 )?;
365 match consumer_error {
366 Some(error) => Err(error),
367 None => Ok(to_execution_control(control)),
368 }
369 }
370
371 fn visit_nodes_by_property_owned(
372 &self,
373 label_id: LabelId,
374 property: &str,
375 values: &[hawdb_core::Value],
376 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
377 ) -> Result<ScanControl> {
378 let mut consumer_error = None;
379 let control =
380 GraphStore::visit_nodes_by_property_owned(self, label_id, property, values, |node| {
381 match consumer(node) {
382 Ok(control) => to_store_control(control),
383 Err(error) => {
384 consumer_error = Some(error);
385 GraphScanControl::Stop
386 }
387 }
388 })?;
389 match consumer_error {
390 Some(error) => Err(error),
391 None => Ok(to_execution_control(control)),
392 }
393 }
394
395 fn visit_nodes_by_composite_property_owned(
396 &self,
397 label_id: LabelId,
398 predicates: &[(String, hawdb_core::Value)],
399 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
400 ) -> Result<ScanControl> {
401 adapt_node_consumer(consumer, |consumer| {
402 GraphStore::visit_nodes_by_composite_property_owned(
403 self, label_id, predicates, consumer,
404 )
405 })
406 }
407
408 fn visit_nodes_by_composite_range_owned(
409 &self,
410 label_id: LabelId,
411 seek: &hawdb_plan_cypher::CompositeRangeSeek,
412 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
413 ) -> Result<ScanControl> {
414 adapt_node_consumer(consumer, |consumer| {
415 GraphStore::visit_nodes_by_composite_range_owned(self, label_id, seek, consumer)
416 })
417 }
418
419 fn visit_nodes_by_property_range_owned(
420 &self,
421 label_id: LabelId,
422 property: &str,
423 lower: Option<&(hawdb_core::Value, bool)>,
424 upper: Option<&(hawdb_core::Value, bool)>,
425 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
426 ) -> Result<ScanControl> {
427 adapt_node_consumer(consumer, |consumer| {
428 GraphStore::visit_nodes_by_property_range_owned(
429 self, label_id, property, lower, upper, consumer,
430 )
431 })
432 }
433
434 fn visit_nodes_by_full_text_property_owned(
435 &self,
436 label_id: LabelId,
437 property: &str,
438 query: &str,
439 consumer: &mut dyn FnMut(NodeRecord) -> Result<ScanControl>,
440 ) -> Result<ScanControl> {
441 adapt_node_consumer(consumer, |consumer| {
442 GraphStore::visit_nodes_by_full_text_property_owned(
443 self, label_id, property, query, consumer,
444 )
445 })
446 }
447
448 fn projected_graph_definition(
449 &self,
450 name: &str,
451 ) -> Option<hawdb_storage::projection::ProjectedGraphDefinition> {
452 GraphStore::projected_graph_definition(self, name).cloned()
453 }
454
455 fn visit_source_scan_candidates(
456 &self,
457 predicate: &hawdb_storage::scan::ScanPredicate,
458 limits: SourceScanReadLimits,
459 task_context: Option<&hawdb_core::RuntimeTaskContext>,
460 consumer: &mut dyn FnMut(SourceScanCandidateRow) -> Result<ScanControl>,
461 ) -> Result<SourceScanCandidateVisit> {
462 let mut consumer_error = None;
463 let visit = GraphStore::visit_published_source_scan_candidates_bounded(
464 self,
465 predicate,
466 hawdb_storage::store::SourceScanCandidateLimits::bounded(
467 limits.io_depth,
468 limits.max_coalesced_bytes,
469 limits.max_wave_bytes,
470 limits.max_live_candidate_bytes,
471 ),
472 task_context,
473 &mut |row| match consumer(SourceScanCandidateRow {
474 node_id: row.node_id,
475 properties: row.properties,
476 }) {
477 Ok(control) => Ok(to_store_control(control)),
478 Err(error) => {
479 consumer_error = Some(error);
480 Ok(hawdb_storage::store::GraphScanControl::Stop)
481 }
482 },
483 )?;
484 if let Some(error) = consumer_error {
485 return Err(error);
486 }
487 Ok(match visit {
488 hawdb_storage::store::SourceScanCandidateVisit::Rows {
489 graph_epoch,
490 skipped_segment_count,
491 report,
492 candidate_count,
493 } => SourceScanCandidateVisit::Rows {
494 graph_epoch,
495 skipped_segment_count,
496 report,
497 candidate_count,
498 },
499 hawdb_storage::store::SourceScanCandidateVisit::Fallback(reason) => {
500 SourceScanCandidateVisit::Fallback(reason)
501 }
502 })
503 }
504
505 fn visit_adjacent_relationships_owned(
506 &self,
507 node_id: NodeId,
508 rel_type: Option<RelTypeId>,
509 direction: AdjacencyDirection,
510 consumer: &mut dyn FnMut(RelRecord) -> Result<ScanControl>,
511 ) -> Result<ScanControl> {
512 GraphStore::try_visit_adjacent_relationships_owned(
513 self,
514 node_id,
515 rel_type,
516 direction,
517 |relationship| consumer(relationship).map(to_store_control),
518 )
519 .map(to_execution_control)
520 }
521
522 fn visit_ordered_adjacent_relationships_owned(
523 &self,
524 node_id: NodeId,
525 rel_type: Option<RelTypeId>,
526 direction: AdjacencyDirection,
527 memory: AdjacencyReadMemory<'_>,
528 consumer: &mut dyn FnMut(RelRecord) -> Result<ScanControl>,
529 ) -> Result<ScanControl> {
530 GraphExecutionRead::visit_ordered_adjacent_relationships_with_allocation(
531 self,
532 node_id,
533 rel_type,
534 direction,
535 memory,
536 &mut hawdb_storage::read_view::ControlledGraphReadAllocator::new(
537 &mut |bytes| memory.admit_node(bytes, 0, None).map(Some),
538 None,
539 ),
540 &mut |relationship| {
541 let (relationship, _allocation) = relationship.into_parts();
542 consumer(relationship)
543 },
544 )
545 }
546
547 fn visit_ordered_adjacent_relationships_with_allocation(
548 &self,
549 node_id: NodeId,
550 rel_type: Option<RelTypeId>,
551 direction: AdjacencyDirection,
552 memory: AdjacencyReadMemory<'_>,
553 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
554 consumer: &mut dyn FnMut(
555 hawdb_storage::read_view::AdmittedRelationshipRecord,
556 ) -> Result<ScanControl>,
557 ) -> Result<ScanControl> {
558 GraphStore::visit_ordered_adjacent_relationships_with_allocation(
559 self,
560 node_id,
561 rel_type,
562 direction,
563 memory.budget_bytes,
564 admit,
565 |relationship| consumer(relationship).map(to_store_control),
566 )
567 .map(to_execution_control)
568 }
569
570 fn visit_filtered_ordered_relationships_with_allocation(
571 &self,
572 adjacency: (NodeId, Option<RelTypeId>, AdjacencyDirection),
573 filter: &PropertyFilter,
574 memory: AdjacencyReadMemory<'_>,
575 admit: &mut hawdb_storage::read_view::ControlledGraphReadAllocator<'_>,
576 consumer: &mut dyn FnMut(
577 hawdb_storage::read_view::AdmittedRelationshipRecord,
578 ) -> Result<ScanControl>,
579 ) -> Result<(ScanControl, Option<hawdb_storage::scan::ScanPruningReport>)> {
580 GraphStore::visit_filtered_ordered_relationships_with_allocation(
581 self,
582 adjacency,
583 filter,
584 memory.budget_bytes,
585 admit,
586 |row| consumer(row).map(to_store_control),
587 )
588 .map(|(control, report)| (to_execution_control(control), report))
589 }
590
591 fn visit_adjacent_relationships_with_filter_owned(
592 &self,
593 node_id: NodeId,
594 rel_type: Option<RelTypeId>,
595 direction: AdjacencyDirection,
596 filter: &PropertyFilter,
597 consumer: &mut dyn FnMut(RelRecord) -> Result<ScanControl>,
598 ) -> Result<(ScanControl, Option<hawdb_storage::scan::ScanPruningReport>)> {
599 let mut consumer_error = None;
600 let (control, report) = GraphStore::visit_adjacent_relationships_with_filter_owned(
601 self,
602 node_id,
603 rel_type,
604 direction,
605 filter,
606 |relationship| match consumer(relationship) {
607 Ok(control) => to_store_control(control),
608 Err(error) => {
609 consumer_error = Some(error);
610 GraphScanControl::Stop
611 }
612 },
613 )?;
614 match consumer_error {
615 Some(error) => Err(error),
616 None => Ok((to_execution_control(control), report)),
617 }
618 }
619
620 fn visit_ordered_adjacent_relationships_with_filter_owned(
621 &self,
622 node_id: NodeId,
623 rel_type: Option<RelTypeId>,
624 direction: AdjacencyDirection,
625 filter: &PropertyFilter,
626 memory: AdjacencyReadMemory<'_>,
627 consumer: &mut dyn FnMut(RelRecord) -> Result<ScanControl>,
628 ) -> Result<(ScanControl, Option<hawdb_storage::scan::ScanPruningReport>)> {
629 GraphStore::visit_filtered_ordered_relationships_with_allocation(
630 self,
631 (node_id, rel_type, direction),
632 filter,
633 memory.budget_bytes,
634 &mut hawdb_storage::read_view::ControlledGraphReadAllocator::new(
635 &mut |bytes| memory.admit_node(bytes, 0, None).map(Some),
636 None,
637 ),
638 |row| {
639 let (relationship, _allocation) = row.into_parts();
640 consumer(relationship).map(to_store_control)
641 },
642 )
643 .map(|(control, report)| (to_execution_control(control), report))
644 }
645
646 fn visit_relationships_owned(
647 &self,
648 rel_type: Option<RelTypeId>,
649 consumer: &mut dyn FnMut(RelRecord) -> Result<ScanControl>,
650 ) -> Result<ScanControl> {
651 GraphStore::try_visit_relationships_owned(self, rel_type, |relationship| {
652 consumer(relationship).map(to_store_control)
653 })
654 .map(to_execution_control)
655 }
656
657 fn scan_relationships_with_filter_pruning<'a>(
658 &'a self,
659 rel_type: Option<RelTypeId>,
660 filter: Option<&PropertyFilter>,
661 ) -> Result<PrunedRelationshipScan<'a>> {
662 let scan = GraphStore::scan_relationships_with_filter_pruning(self, rel_type, filter);
663 Ok(PrunedRelationshipScan {
664 relationships: Box::new(scan.relationships.into_iter().cloned()),
665 report: scan.report,
666 })
667 }
668
669 fn scan_nodes_with_filter_pruning<'a>(
670 &'a self,
671 catalog: &Catalog,
672 label_id: Option<LabelId>,
673 filter: Option<&PropertyFilter>,
674 ) -> Result<PrunedNodeScan<'a>> {
675 let scan = GraphStore::scan_nodes_with_filter_pruning(self, catalog, label_id, filter);
676 Ok(PrunedNodeScan {
677 nodes: Box::new(scan.nodes.into_iter().map(std::borrow::Cow::Borrowed)),
678 report: scan.report,
679 })
680 }
681
682 fn scan_nodes_with_filter_pruning_admitted<'a>(
683 &'a self,
684 catalog: &Catalog,
685 label_id: Option<LabelId>,
686 filter: Option<&PropertyFilter>,
687 admit: &mut dyn FnMut(
688 usize,
689 )
690 -> Result<Box<dyn hawdb_storage::read_view::GraphReadAllocation>>,
691 ) -> Result<PrunedNodeScan<'a>> {
692 let (scan, allocation) = GraphStore::scan_nodes_with_filter_pruning_admitted(
693 self, catalog, label_id, filter, admit,
694 )?;
695 Ok(PrunedNodeScan {
696 nodes: Box::new(scan.nodes.into_iter().map(move |node| {
697 let _retained_allocation = &allocation;
698 std::borrow::Cow::Borrowed(node)
699 })),
700 report: scan.report,
701 })
702 }
703}
704
705impl GraphExecutionWrite for GraphStore {
706 fn commit_mutation_with_limits(
707 &mut self,
708 catalog: &mut Catalog,
709 mutation: GraphMutation,
710 limits: MutationLimits,
711 ) -> Result<MutationSummary> {
712 GraphStore::commit_mutation_with_limits(self, catalog, mutation, limits)
713 }
714
715 fn commit_mutations_with_limits(
716 &mut self,
717 catalog: &mut Catalog,
718 mutations: Vec<GraphMutation>,
719 limits: MutationLimits,
720 ) -> Result<MutationSummary> {
721 GraphStore::commit_mutations_with_limits(self, catalog, mutations, limits)
722 }
723
724 fn set_node_properties_by_ids_with_limits(
725 &mut self,
726 catalog: &mut Catalog,
727 ids: &[NodeId],
728 assignments: &[NodeSetAssignment],
729 limits: MutationLimits,
730 ) -> Result<Vec<NodeId>> {
731 GraphStore::set_node_properties_by_ids_with_limits(self, catalog, ids, assignments, limits)
732 }
733
734 fn delete_node_ids_with_limits(
735 &mut self,
736 catalog: &mut Catalog,
737 ids: &[NodeId],
738 detach: bool,
739 limits: MutationLimits,
740 ) -> Result<Vec<NodeId>> {
741 GraphStore::delete_node_ids_with_limits(self, catalog, ids, detach, limits)
742 }
743}