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