Skip to main content

selene_gql/analyze/
write_set.rs

1//! Mutation write-set enumeration.
2
3use selene_core::DbString;
4
5use crate::{
6    DeleteMode, LabelExpr, SourceSpan, ValueExpr,
7    analyze::binding::{BindingDeclKind, BindingId},
8};
9
10/// Enumerated per-pipeline summary of writes produced by a mutation statement.
11#[derive(Clone, Debug, Default, Eq, PartialEq)]
12pub struct MutationWriteSet {
13    /// Each source write site emits one entry.
14    pub entries: Vec<WriteSetEntry>,
15}
16
17impl MutationWriteSet {
18    pub(crate) fn push(&mut self, entry: WriteSetEntry) {
19        self.entries.push(entry);
20    }
21}
22
23/// One write site in a mutation pipeline.
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct WriteSetEntry {
26    /// Zero-based mutation-statement index within the owning pipeline.
27    pub statement_index: usize,
28    /// Source span of the write site.
29    pub span: SourceSpan,
30    /// Kind of write.
31    pub kind: WriteKind,
32}
33
34/// Structural write operation recorded by the analyzer.
35#[derive(Clone, Debug, Eq, PartialEq)]
36#[non_exhaustive]
37pub enum WriteKind {
38    /// `INSERT` introduces a node. Anonymous inserts carry no binding.
39    InsertNode {
40        /// Inserted-node binding, when the pattern names one.
41        binding: Option<BindingId>,
42        /// Static label expression declared on the pattern.
43        label_expr: Option<LabelExpr>,
44        /// Property keys written by the inline property map.
45        property_keys: Box<[DbString]>,
46    },
47    /// `INSERT` introduces an edge. Anonymous inserts carry no binding.
48    InsertEdge {
49        /// Inserted-edge binding, when the pattern names one.
50        binding: Option<BindingId>,
51        /// Static label expression declared on the pattern.
52        label_expr: Option<LabelExpr>,
53        /// Property keys written by the inline property map.
54        property_keys: Box<[DbString]>,
55    },
56    /// `SET n.key = expr` or `SET n = { key: expr }`.
57    SetProperty {
58        /// Resolved target binding.
59        target: BindingId,
60        /// Element kind of the resolved target.
61        element: ElementKind,
62        /// Property key being written.
63        key: DbString,
64        /// Source span of the value expression for this specific write.
65        value_span: SourceSpan,
66    },
67    /// `SET n :Label`.
68    SetLabel {
69        /// Resolved target binding.
70        target: BindingId,
71        /// Element kind of the resolved target.
72        element: ElementKind,
73        /// Label being added.
74        label: DbString,
75    },
76    /// `REMOVE n.key`.
77    RemoveProperty {
78        /// Resolved target binding.
79        target: BindingId,
80        /// Element kind of the resolved target.
81        element: ElementKind,
82        /// Property key being removed.
83        key: DbString,
84    },
85    /// `REMOVE n :Label`.
86    RemoveLabel {
87        /// Resolved target binding.
88        target: BindingId,
89        /// Element kind of the resolved target.
90        element: ElementKind,
91        /// Label being removed.
92        label: DbString,
93    },
94    /// `DELETE n` / `DETACH DELETE n` / `NODETACH DELETE n`.
95    DeleteTarget {
96        /// Resolved target binding.
97        target: BindingId,
98        /// Element kind of the resolved target.
99        element: ElementKind,
100        /// Delete mode requested by syntax.
101        mode: DeleteMode,
102    },
103}
104
105/// Element kind of a resolved write target.
106#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
107pub enum ElementKind {
108    /// Node binding.
109    Node,
110    /// Edge binding.
111    Edge,
112    /// Path binding.
113    Path,
114    /// Value alias or procedure output column.
115    Alias,
116}
117
118impl ElementKind {
119    /// Convert a binding declaration kind to its write-target element kind.
120    #[must_use]
121    pub const fn from_decl_kind(kind: BindingDeclKind) -> Self {
122        match kind {
123            BindingDeclKind::NodePattern | BindingDeclKind::InsertNode => Self::Node,
124            BindingDeclKind::EdgePattern | BindingDeclKind::InsertEdge => Self::Edge,
125            BindingDeclKind::PathBinding => Self::Path,
126            BindingDeclKind::LetAlias
127            | BindingDeclKind::ForAlias
128            | BindingDeclKind::ProjectionAlias
129            | BindingDeclKind::YieldColumn => Self::Alias,
130        }
131    }
132}
133
134pub(crate) fn property_keys(properties: &[(DbString, ValueExpr)]) -> Box<[DbString]> {
135    properties
136        .iter()
137        .map(|(key, _)| key.clone())
138        .collect::<Vec<_>>()
139        .into_boxed_slice()
140}