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