jellyflow_runtime/rules/
plans.rs1use serde::{Deserialize, Serialize};
2
3use jellyflow_core::ops::GraphOp;
4
5use super::{Diagnostic, DiagnosticTarget};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum ConnectDecision {
11 Accept,
13 Reject,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[serde(rename_all = "snake_case")]
20pub enum DeleteDecision {
21 Accept,
23 Reject,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
29#[serde(rename_all = "snake_case")]
30pub enum EdgeEndpoint {
31 From,
33 To,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ConnectPlan {
40 pub decision: ConnectDecision,
42 #[serde(default, skip_serializing_if = "Vec::is_empty")]
44 pub diagnostics: Vec<Diagnostic>,
45 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub ops: Vec<GraphOp>,
48}
49
50impl ConnectPlan {
51 pub fn is_accept(&self) -> bool {
52 self.decision == ConnectDecision::Accept
53 }
54
55 pub fn is_reject(&self) -> bool {
56 self.decision == ConnectDecision::Reject
57 }
58
59 pub fn diagnostics(&self) -> &[Diagnostic] {
60 &self.diagnostics
61 }
62
63 pub fn ops(&self) -> &[GraphOp] {
64 &self.ops
65 }
66
67 pub fn into_ops(self) -> Vec<GraphOp> {
68 self.ops
69 }
70
71 pub fn accept() -> Self {
73 Self {
74 decision: ConnectDecision::Accept,
75 diagnostics: Vec::new(),
76 ops: Vec::new(),
77 }
78 }
79
80 pub fn from_ops(ops: impl IntoIterator<Item = GraphOp>) -> Self {
82 Self {
83 decision: ConnectDecision::Accept,
84 diagnostics: Vec::new(),
85 ops: ops.into_iter().collect(),
86 }
87 }
88
89 pub fn reject(message: impl Into<String>) -> Self {
91 Self::reject_with_diagnostic(Diagnostic::error(
92 "connect.rejected",
93 DiagnosticTarget::Graph,
94 message,
95 ))
96 }
97
98 pub fn reject_with_diagnostic(diagnostic: Diagnostic) -> Self {
99 Self::reject_with_diagnostics(vec![diagnostic])
100 }
101
102 pub fn reject_with_diagnostics(diagnostics: Vec<Diagnostic>) -> Self {
103 Self {
104 decision: ConnectDecision::Reject,
105 diagnostics,
106 ops: Vec::new(),
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct DeletePlan {
119 pub decision: DeleteDecision,
121 #[serde(default, skip_serializing_if = "Vec::is_empty")]
123 pub diagnostics: Vec<Diagnostic>,
124 #[serde(default, skip_serializing_if = "Vec::is_empty")]
126 pub ops: Vec<GraphOp>,
127}
128
129impl DeletePlan {
130 pub fn is_accept(&self) -> bool {
131 self.decision == DeleteDecision::Accept
132 }
133
134 pub fn is_reject(&self) -> bool {
135 self.decision == DeleteDecision::Reject
136 }
137
138 pub fn diagnostics(&self) -> &[Diagnostic] {
139 &self.diagnostics
140 }
141
142 pub fn ops(&self) -> &[GraphOp] {
143 &self.ops
144 }
145
146 pub fn into_ops(self) -> Vec<GraphOp> {
147 self.ops
148 }
149
150 pub fn accept() -> Self {
152 Self {
153 decision: DeleteDecision::Accept,
154 diagnostics: Vec::new(),
155 ops: Vec::new(),
156 }
157 }
158
159 pub fn from_ops(ops: impl IntoIterator<Item = GraphOp>) -> Self {
161 Self {
162 decision: DeleteDecision::Accept,
163 diagnostics: Vec::new(),
164 ops: ops.into_iter().collect(),
165 }
166 }
167
168 pub fn reject(message: impl Into<String>) -> Self {
170 Self::reject_with_diagnostic(Diagnostic::error(
171 "delete.rejected",
172 DiagnosticTarget::Graph,
173 message,
174 ))
175 }
176
177 pub fn reject_with_diagnostic(diagnostic: Diagnostic) -> Self {
178 Self::reject_with_diagnostics(vec![diagnostic])
179 }
180
181 pub fn reject_with_diagnostics(diagnostics: Vec<Diagnostic>) -> Self {
182 Self {
183 decision: DeleteDecision::Reject,
184 diagnostics,
185 ops: Vec::new(),
186 }
187 }
188}