1use crate::algebra::*;
2use crate::parser::{parse_update, SparqlSyntaxError};
3use crate::term::*;
4use oxiri::Iri;
5use std::fmt;
6use std::str::FromStr;
7
8#[derive(Eq, PartialEq, Debug, Clone, Hash)]
20pub struct Update {
21 pub base_iri: Option<Iri<String>>,
23 pub operations: Vec<GraphUpdateOperation>,
25}
26
27impl Update {
28 pub fn parse(update: &str, base_iri: Option<&str>) -> Result<Self, SparqlSyntaxError> {
30 parse_update(update, base_iri)
31 }
32
33 pub fn to_sse(&self) -> String {
35 let mut buffer = String::new();
36 self.fmt_sse(&mut buffer).unwrap();
37 buffer
38 }
39
40 fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
42 if let Some(base_iri) = &self.base_iri {
43 write!(f, "(base <{base_iri}> ")?;
44 }
45 f.write_str("(update")?;
46 for op in &self.operations {
47 f.write_str(" ")?;
48 op.fmt_sse(f)?;
49 }
50 f.write_str(")")?;
51 if self.base_iri.is_some() {
52 f.write_str(")")?;
53 }
54 Ok(())
55 }
56}
57
58impl fmt::Display for Update {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 if let Some(base_iri) = &self.base_iri {
61 writeln!(f, "BASE <{base_iri}>")?;
62 }
63 for update in &self.operations {
64 writeln!(f, "{update} ;")?;
65 }
66 Ok(())
67 }
68}
69
70impl FromStr for Update {
71 type Err = SparqlSyntaxError;
72
73 fn from_str(update: &str) -> Result<Self, Self::Err> {
74 Self::parse(update, None)
75 }
76}
77
78impl TryFrom<&str> for Update {
79 type Error = SparqlSyntaxError;
80
81 fn try_from(update: &str) -> Result<Self, Self::Error> {
82 Self::from_str(update)
83 }
84}
85
86impl TryFrom<&String> for Update {
87 type Error = SparqlSyntaxError;
88
89 fn try_from(update: &String) -> Result<Self, Self::Error> {
90 Self::from_str(update)
91 }
92}
93
94#[derive(Eq, PartialEq, Debug, Clone, Hash)]
96pub enum GraphUpdateOperation {
97 InsertData { data: Vec<Quad> },
99 DeleteData { data: Vec<GroundQuad> },
101 DeleteInsert {
103 delete: Vec<GroundQuadPattern>,
104 insert: Vec<QuadPattern>,
105 using: Option<QueryDataset>,
106 pattern: Box<GraphPattern>,
107 },
108 Load {
110 silent: bool,
111 source: NamedNode,
112 destination: GraphName,
113 },
114 Clear { silent: bool, graph: GraphTarget },
116 Create { silent: bool, graph: NamedNode },
118 Drop { silent: bool, graph: GraphTarget },
120}
121
122impl GraphUpdateOperation {
123 fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
125 match self {
126 Self::InsertData { data } => {
127 f.write_str("(insertData (")?;
128 for (i, t) in data.iter().enumerate() {
129 if i > 0 {
130 f.write_str(" ")?;
131 }
132 t.fmt_sse(f)?;
133 }
134 f.write_str("))")
135 }
136 Self::DeleteData { data } => {
137 f.write_str("(deleteData (")?;
138 for (i, t) in data.iter().enumerate() {
139 if i > 0 {
140 f.write_str(" ")?;
141 }
142 t.fmt_sse(f)?;
143 }
144 f.write_str("))")
145 }
146 Self::DeleteInsert {
147 delete,
148 insert,
149 using,
150 pattern,
151 } => {
152 f.write_str("(modify ")?;
153 if let Some(using) = using {
154 f.write_str(" (using ")?;
155 using.fmt_sse(f)?;
156 f.write_str(" ")?;
157 pattern.fmt_sse(f)?;
158 f.write_str(")")?;
159 } else {
160 pattern.fmt_sse(f)?;
161 }
162 if !delete.is_empty() {
163 f.write_str(" (delete (")?;
164 for (i, t) in delete.iter().enumerate() {
165 if i > 0 {
166 f.write_str(" ")?;
167 }
168 t.fmt_sse(f)?;
169 }
170 f.write_str("))")?;
171 }
172 if !insert.is_empty() {
173 f.write_str(" (insert (")?;
174 for (i, t) in insert.iter().enumerate() {
175 if i > 0 {
176 f.write_str(" ")?;
177 }
178 t.fmt_sse(f)?;
179 }
180 f.write_str("))")?;
181 }
182 f.write_str(")")
183 }
184 Self::Load {
185 silent,
186 source,
187 destination,
188 } => {
189 f.write_str("(load ")?;
190 if *silent {
191 f.write_str("silent ")?;
192 }
193 write!(f, "{source} ")?;
194 destination.fmt_sse(f)?;
195 f.write_str(")")
196 }
197 Self::Clear { silent, graph } => {
198 f.write_str("(clear ")?;
199 if *silent {
200 f.write_str("silent ")?;
201 }
202 graph.fmt_sse(f)?;
203 f.write_str(")")
204 }
205 Self::Create { silent, graph } => {
206 f.write_str("(create ")?;
207 if *silent {
208 f.write_str("silent ")?;
209 }
210 write!(f, "{graph})")
211 }
212 Self::Drop { silent, graph } => {
213 f.write_str("(drop ")?;
214 if *silent {
215 f.write_str("silent ")?;
216 }
217 graph.fmt_sse(f)?;
218 f.write_str(")")
219 }
220 }
221 }
222}
223
224impl fmt::Display for GraphUpdateOperation {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 match self {
227 Self::InsertData { data } => {
228 writeln!(f, "INSERT DATA {{")?;
229 serialize_quads(data, f)?;
230 f.write_str("}")
231 }
232 Self::DeleteData { data } => {
233 writeln!(f, "DELETE DATA {{")?;
234 write_ground_quads(data, f)?;
235 f.write_str("}")
236 }
237 Self::DeleteInsert {
238 delete,
239 insert,
240 using,
241 pattern,
242 } => {
243 if !delete.is_empty() {
244 writeln!(f, "DELETE {{")?;
245 for quad in delete {
246 writeln!(f, "\t{quad} .")?;
247 }
248 writeln!(f, "}}")?;
249 }
250 if !insert.is_empty() {
251 writeln!(f, "INSERT {{")?;
252 for quad in insert {
253 writeln!(f, "\t{quad} .")?;
254 }
255 writeln!(f, "}}")?;
256 }
257 if let Some(using) = using {
258 for g in &using.default {
259 writeln!(f, "USING {g}")?;
260 }
261 if let Some(named) = &using.named {
262 for g in named {
263 writeln!(f, "USING NAMED {g}")?;
264 }
265 }
266 }
267 write!(
268 f,
269 "WHERE {{ {} }}",
270 SparqlGraphRootPattern::new(pattern, None)
271 )
272 }
273 Self::Load {
274 silent,
275 source,
276 destination,
277 } => {
278 f.write_str("LOAD ")?;
279 if *silent {
280 f.write_str("SILENT ")?;
281 }
282 write!(f, "{source}")?;
283 if destination != &GraphName::DefaultGraph {
284 write!(f, " INTO GRAPH {destination}")?;
285 }
286 Ok(())
287 }
288 Self::Clear { silent, graph } => {
289 f.write_str("CLEAR ")?;
290 if *silent {
291 f.write_str("SILENT ")?;
292 }
293 write!(f, "{graph}")
294 }
295 Self::Create { silent, graph } => {
296 f.write_str("CREATE ")?;
297 if *silent {
298 f.write_str("SILENT ")?;
299 }
300 write!(f, "GRAPH {graph}")
301 }
302 Self::Drop { silent, graph } => {
303 f.write_str("DROP ")?;
304 if *silent {
305 f.write_str("SILENT ")?;
306 }
307 write!(f, "{graph}")
308 }
309 }
310 }
311}
312
313fn serialize_quads(quads: &[Quad], f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 for quad in quads {
315 if quad.graph_name == GraphName::DefaultGraph {
316 writeln!(f, "\t{} {} {} .", quad.subject, quad.predicate, quad.object)?;
317 } else {
318 writeln!(
319 f,
320 "\tGRAPH {} {{ {} {} {} }}",
321 quad.graph_name, quad.subject, quad.predicate, quad.object
322 )?;
323 }
324 }
325 Ok(())
326}
327
328fn write_ground_quads(quads: &[GroundQuad], f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 for quad in quads {
330 if quad.graph_name == GraphName::DefaultGraph {
331 writeln!(f, "\t{} {} {} .", quad.subject, quad.predicate, quad.object)?;
332 } else {
333 writeln!(
334 f,
335 "\tGRAPH {} {{ {} {} {} }}",
336 quad.graph_name, quad.subject, quad.predicate, quad.object
337 )?;
338 }
339 }
340 Ok(())
341}