1use crate::model::{BlankNode, Literal, NamedNode, Object, Predicate, Subject, Triple, Variable};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct TriplePattern {
11 pub subject: Option<SubjectPattern>,
12 pub predicate: Option<PredicatePattern>,
13 pub object: Option<ObjectPattern>,
14}
15
16impl TriplePattern {
17 pub fn new(
19 subject: Option<SubjectPattern>,
20 predicate: Option<PredicatePattern>,
21 object: Option<ObjectPattern>,
22 ) -> Self {
23 TriplePattern {
24 subject,
25 predicate,
26 object,
27 }
28 }
29
30 pub fn subject(&self) -> Option<&SubjectPattern> {
32 self.subject.as_ref()
33 }
34
35 pub fn predicate(&self) -> Option<&PredicatePattern> {
37 self.predicate.as_ref()
38 }
39
40 pub fn object(&self) -> Option<&ObjectPattern> {
42 self.object.as_ref()
43 }
44
45 pub fn matches(&self, triple: &Triple) -> bool {
47 if let Some(ref subject_pattern) = self.subject {
49 if !subject_pattern.matches(triple.subject()) {
50 return false;
51 }
52 }
53
54 if let Some(ref predicate_pattern) = self.predicate {
56 if !predicate_pattern.matches(triple.predicate()) {
57 return false;
58 }
59 }
60
61 if let Some(ref object_pattern) = self.object {
63 if !object_pattern.matches(triple.object()) {
64 return false;
65 }
66 }
67
68 true
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75pub enum SubjectPattern {
76 NamedNode(NamedNode),
77 BlankNode(BlankNode),
78 Variable(Variable),
79 QuotedTriple(Box<crate::query::algebra::AlgebraTriplePattern>),
81}
82
83impl SubjectPattern {
84 pub fn as_str(&self) -> &str {
86 match self {
87 SubjectPattern::NamedNode(nn) => nn.as_str(),
88 SubjectPattern::BlankNode(bn) => bn.as_str(),
89 SubjectPattern::Variable(v) => v.as_str(),
90 SubjectPattern::QuotedTriple(_) => "<<quoted-triple>>",
91 }
92 }
93
94 fn matches(&self, subject: &Subject) -> bool {
95 match (self, subject) {
96 (SubjectPattern::NamedNode(pn), Subject::NamedNode(sn)) => pn == sn,
97 (SubjectPattern::BlankNode(pb), Subject::BlankNode(sb)) => pb == sb,
98 (SubjectPattern::Variable(_), _) => true,
99 (SubjectPattern::QuotedTriple(_), Subject::QuotedTriple(_)) => true,
102 _ => false,
103 }
104 }
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Hash)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
110pub enum PredicatePattern {
111 NamedNode(NamedNode),
112 Variable(Variable),
113}
114
115impl PredicatePattern {
116 pub fn as_str(&self) -> &str {
118 match self {
119 PredicatePattern::NamedNode(nn) => nn.as_str(),
120 PredicatePattern::Variable(v) => v.as_str(),
121 }
122 }
123
124 fn matches(&self, predicate: &Predicate) -> bool {
125 match (self, predicate) {
126 (PredicatePattern::NamedNode(pn), Predicate::NamedNode(sn)) => pn == sn,
127 (PredicatePattern::Variable(_), _) => true,
128 _ => false,
129 }
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Hash)]
135#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136pub enum ObjectPattern {
137 NamedNode(NamedNode),
138 BlankNode(BlankNode),
139 Literal(Literal),
140 Variable(Variable),
141 QuotedTriple(Box<crate::query::algebra::AlgebraTriplePattern>),
143}
144
145impl ObjectPattern {
146 pub fn as_str(&self) -> &str {
148 match self {
149 ObjectPattern::NamedNode(nn) => nn.as_str(),
150 ObjectPattern::BlankNode(bn) => bn.as_str(),
151 ObjectPattern::Literal(l) => l.value(),
152 ObjectPattern::Variable(v) => v.as_str(),
153 ObjectPattern::QuotedTriple(_) => "<<quoted-triple>>",
154 }
155 }
156
157 fn matches(&self, object: &Object) -> bool {
158 match (self, object) {
159 (ObjectPattern::NamedNode(pn), Object::NamedNode(on)) => pn == on,
160 (ObjectPattern::BlankNode(pb), Object::BlankNode(ob)) => pb == ob,
161 (ObjectPattern::Literal(pl), Object::Literal(ol)) => pl == ol,
162 (ObjectPattern::Variable(_), _) => true,
163 (ObjectPattern::QuotedTriple(_), Object::QuotedTriple(_)) => true,
165 _ => false,
166 }
167 }
168}
169
170use crate::query::algebra::TermPattern;
174
175#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct InvalidPatternConversion {
178 pub reason: &'static str,
179}
180
181impl std::fmt::Display for InvalidPatternConversion {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "Invalid pattern conversion: {}", self.reason)
184 }
185}
186
187impl std::error::Error for InvalidPatternConversion {}
188
189impl TryFrom<TermPattern> for SubjectPattern {
190 type Error = InvalidPatternConversion;
191
192 fn try_from(term: TermPattern) -> Result<Self, Self::Error> {
193 match term {
194 TermPattern::NamedNode(n) => Ok(SubjectPattern::NamedNode(n)),
195 TermPattern::BlankNode(b) => Ok(SubjectPattern::BlankNode(b)),
196 TermPattern::Variable(v) => Ok(SubjectPattern::Variable(v)),
197 TermPattern::QuotedTriple(qt) => Ok(SubjectPattern::QuotedTriple(qt)),
198 TermPattern::Literal(_) => Err(InvalidPatternConversion {
199 reason: "Literals cannot be used as subjects in RDF",
200 }),
201 }
202 }
203}
204
205impl TryFrom<TermPattern> for PredicatePattern {
206 type Error = InvalidPatternConversion;
207
208 fn try_from(term: TermPattern) -> Result<Self, Self::Error> {
209 match term {
210 TermPattern::NamedNode(n) => Ok(PredicatePattern::NamedNode(n)),
211 TermPattern::Variable(v) => Ok(PredicatePattern::Variable(v)),
212 TermPattern::BlankNode(_) => Err(InvalidPatternConversion {
213 reason: "Blank nodes cannot be used as predicates in RDF",
214 }),
215 TermPattern::Literal(_) => Err(InvalidPatternConversion {
216 reason: "Literals cannot be used as predicates in RDF",
217 }),
218 TermPattern::QuotedTriple(_) => Err(InvalidPatternConversion {
219 reason: "Quoted triples cannot be used as predicates in RDF",
220 }),
221 }
222 }
223}
224
225impl TryFrom<TermPattern> for ObjectPattern {
226 type Error = InvalidPatternConversion;
227
228 fn try_from(term: TermPattern) -> Result<Self, Self::Error> {
229 match term {
230 TermPattern::NamedNode(n) => Ok(ObjectPattern::NamedNode(n)),
231 TermPattern::BlankNode(b) => Ok(ObjectPattern::BlankNode(b)),
232 TermPattern::Literal(l) => Ok(ObjectPattern::Literal(l)),
233 TermPattern::Variable(v) => Ok(ObjectPattern::Variable(v)),
234 TermPattern::QuotedTriple(qt) => Ok(ObjectPattern::QuotedTriple(qt)),
235 }
236 }
237}
238
239impl TryFrom<&SubjectPattern> for Subject {
241 type Error = ();
242
243 fn try_from(pattern: &SubjectPattern) -> Result<Self, Self::Error> {
244 match pattern {
245 SubjectPattern::NamedNode(n) => Ok(Subject::NamedNode(n.clone())),
246 SubjectPattern::BlankNode(b) => Ok(Subject::BlankNode(b.clone())),
247 SubjectPattern::Variable(_) => Err(()),
248 SubjectPattern::QuotedTriple(qt) => {
249 use crate::model::star::QuotedTriple;
252 let inner_subj = match &qt.subject {
253 TermPattern::NamedNode(n) => Subject::NamedNode(n.clone()),
254 TermPattern::BlankNode(b) => Subject::BlankNode(b.clone()),
255 _ => return Err(()),
256 };
257 let inner_pred = match &qt.predicate {
258 TermPattern::NamedNode(n) => Predicate::NamedNode(n.clone()),
259 _ => return Err(()),
260 };
261 let inner_obj = match &qt.object {
262 TermPattern::NamedNode(n) => Object::NamedNode(n.clone()),
263 TermPattern::BlankNode(b) => Object::BlankNode(b.clone()),
264 TermPattern::Literal(l) => Object::Literal(l.clone()),
265 _ => return Err(()),
266 };
267 Ok(Subject::QuotedTriple(Box::new(QuotedTriple::new(
268 Triple::new(inner_subj, inner_pred, inner_obj),
269 ))))
270 }
271 }
272 }
273}
274
275impl TryFrom<&PredicatePattern> for Predicate {
276 type Error = ();
277
278 fn try_from(pattern: &PredicatePattern) -> Result<Self, Self::Error> {
279 match pattern {
280 PredicatePattern::NamedNode(n) => Ok(Predicate::NamedNode(n.clone())),
281 PredicatePattern::Variable(_) => Err(()),
282 }
283 }
284}
285
286impl TryFrom<&ObjectPattern> for Object {
287 type Error = ();
288
289 fn try_from(pattern: &ObjectPattern) -> Result<Self, Self::Error> {
290 match pattern {
291 ObjectPattern::NamedNode(n) => Ok(Object::NamedNode(n.clone())),
292 ObjectPattern::BlankNode(b) => Ok(Object::BlankNode(b.clone())),
293 ObjectPattern::Literal(l) => Ok(Object::Literal(l.clone())),
294 ObjectPattern::Variable(_) => Err(()),
295 ObjectPattern::QuotedTriple(qt) => {
296 use crate::model::star::QuotedTriple;
298 let inner_subj = match &qt.subject {
299 TermPattern::NamedNode(n) => Subject::NamedNode(n.clone()),
300 TermPattern::BlankNode(b) => Subject::BlankNode(b.clone()),
301 _ => return Err(()),
302 };
303 let inner_pred = match &qt.predicate {
304 TermPattern::NamedNode(n) => Predicate::NamedNode(n.clone()),
305 _ => return Err(()),
306 };
307 let inner_obj = match &qt.object {
308 TermPattern::NamedNode(n) => Object::NamedNode(n.clone()),
309 TermPattern::BlankNode(b) => Object::BlankNode(b.clone()),
310 TermPattern::Literal(l) => Object::Literal(l.clone()),
311 _ => return Err(()),
312 };
313 Ok(Object::QuotedTriple(Box::new(QuotedTriple::new(
314 Triple::new(inner_subj, inner_pred, inner_obj),
315 ))))
316 }
317 }
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324
325 #[test]
326 fn test_pattern_matching() {
327 let subject = NamedNode::new("http://example.org/s").expect("valid IRI");
328 let predicate = NamedNode::new("http://example.org/p").expect("valid IRI");
329 let object = Literal::new("o");
330
331 let triple = Triple::new(subject.clone(), predicate.clone(), object.clone());
332
333 let pattern = TriplePattern::new(
335 Some(SubjectPattern::NamedNode(subject.clone())),
336 Some(PredicatePattern::NamedNode(predicate.clone())),
337 Some(ObjectPattern::Literal(object.clone())),
338 );
339 assert!(pattern.matches(&triple));
340
341 let pattern = TriplePattern::new(None, None, None);
343 assert!(pattern.matches(&triple));
344
345 let pattern = TriplePattern::new(
347 Some(SubjectPattern::Variable(
348 Variable::new("s").expect("valid variable name"),
349 )),
350 Some(PredicatePattern::Variable(
351 Variable::new("p").expect("valid variable name"),
352 )),
353 Some(ObjectPattern::Variable(
354 Variable::new("o").expect("valid variable name"),
355 )),
356 );
357 assert!(pattern.matches(&triple));
358
359 let different_subject = NamedNode::new("http://example.org/different").expect("valid IRI");
361 let pattern = TriplePattern::new(
362 Some(SubjectPattern::NamedNode(different_subject)),
363 None,
364 None,
365 );
366 assert!(!pattern.matches(&triple));
367 }
368}