1use crate::{
7 model::*,
8 parser::RdfFormat,
9 rdf_store::{OxirsQueryResults, RdfStore},
10 transaction::{IsolationLevel, TransactionManager},
11 OxirsError, Result, Store as OxirsStoreTrait,
12};
13use std::io::{BufRead, Write};
14use std::path::{Path, PathBuf};
15use std::sync::{Arc, RwLock};
16
17pub struct Store {
23 inner: Arc<RwLock<RdfStore>>,
24 tx_manager: Arc<RwLock<Option<TransactionManager>>>,
25 wal_dir: Option<PathBuf>,
26}
27
28impl Store {
29 pub fn new() -> Result<Self> {
33 Ok(Store {
34 inner: Arc::new(RwLock::new(RdfStore::new()?)),
35 tx_manager: Arc::new(RwLock::new(None)),
36 wal_dir: None,
37 })
38 }
39
40 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
44 let path_buf = path.as_ref().to_path_buf();
45 let wal_dir = path_buf.join("wal");
46
47 Ok(Store {
48 inner: Arc::new(RwLock::new(RdfStore::open(&path_buf)?)),
49 tx_manager: Arc::new(RwLock::new(None)),
50 wal_dir: Some(wal_dir),
51 })
52 }
53
54 pub fn insert<'a>(&self, quad: impl Into<QuadRef<'a>>) -> Result<bool> {
58 let quad_ref = quad.into();
59 let quad = Quad::new(
60 quad_ref.subject().to_owned(),
61 quad_ref.predicate().to_owned(),
62 quad_ref.object().to_owned(),
63 quad_ref.graph_name().to_owned(),
64 );
65
66 let store = self
67 .inner
68 .write()
69 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
70 store.insert_quad(quad)
71 }
72
73 pub fn extend<'a>(
75 &self,
76 quads: impl IntoIterator<Item = impl Into<QuadRef<'a>>>,
77 ) -> Result<()> {
78 let store = self
79 .inner
80 .write()
81 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
82
83 for quad in quads {
84 let quad_ref = quad.into();
85 let quad = Quad::new(
86 quad_ref.subject().to_owned(),
87 quad_ref.predicate().to_owned(),
88 quad_ref.object().to_owned(),
89 quad_ref.graph_name().to_owned(),
90 );
91 store.insert_quad(quad)?;
92 }
93
94 Ok(())
95 }
96
97 pub fn remove<'a>(&self, quad: impl Into<QuadRef<'a>>) -> Result<bool> {
101 let quad_ref = quad.into();
102 let quad = Quad::new(
103 quad_ref.subject().to_owned(),
104 quad_ref.predicate().to_owned(),
105 quad_ref.object().to_owned(),
106 quad_ref.graph_name().to_owned(),
107 );
108
109 let store = self
110 .inner
111 .write()
112 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
113 store.remove_quad(&quad)
114 }
115
116 pub fn load_from_reader<R: BufRead>(
118 &self,
119 reader: R,
120 format: RdfFormat,
121 base_iri: Option<&str>,
122 graph: Option<impl Into<GraphName>>,
123 ) -> Result<()> {
124 use crate::parser::Parser;
125
126 let mut data = String::new();
128 let mut reader = reader;
129 reader
131 .read_to_string(&mut data)
132 .map_err(|e| OxirsError::Parse(format!("Failed to read input: {e}")))?;
133
134 let mut parser = Parser::new(format);
136 if let Some(base) = base_iri {
137 parser = parser.with_base_iri(base);
138 }
139
140 let quads = parser.parse_str_to_quads(&data)?;
142
143 let store = self
145 .inner
146 .write()
147 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
148
149 let target_graph = graph.map(|g| g.into());
151 for quad in quads {
152 let final_quad = if let Some(ref g) = target_graph {
153 Quad::new(
155 quad.subject().clone(),
156 quad.predicate().clone(),
157 quad.object().clone(),
158 g.clone(),
159 )
160 } else {
161 quad
162 };
163 store.insert_quad(final_quad)?;
164 }
165
166 Ok(())
167 }
168
169 pub fn dump_to_writer<'a, W: Write>(
171 &self,
172 mut writer: W,
173 format: RdfFormat,
174 graph: Option<impl Into<GraphNameRef<'a>>>,
175 ) -> Result<()> {
176 use crate::model::{dataset::Dataset, graph::Graph};
177 use crate::serializer::Serializer;
178
179 let store = self
180 .inner
181 .read()
182 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
183
184 let serializer = Serializer::new(format);
185
186 let quads = if let Some(g) = graph {
188 let graph_ref = g.into();
189 let graph_name = graph_ref.to_owned();
190 store.query_quads(None, None, None, Some(&graph_name))?
191 } else {
192 store.iter_quads()?
193 };
194
195 let output = match format {
197 RdfFormat::Turtle | RdfFormat::NTriples | RdfFormat::RdfXml => {
198 let triples: Vec<_> = quads
200 .into_iter()
201 .filter(|q| q.is_default_graph())
202 .map(|q| q.to_triple())
203 .collect();
204 let graph = Graph::from_iter(triples);
205 serializer.serialize_graph(&graph)?
206 }
207 RdfFormat::TriG | RdfFormat::NQuads | RdfFormat::JsonLd => {
208 let dataset = Dataset::from_iter(quads);
210 serializer.serialize_dataset(&dataset)?
211 }
212 };
213
214 writer
215 .write_all(output.as_bytes())
216 .map_err(|e| OxirsError::Serialize(format!("Failed to write output: {e}")))?;
217
218 Ok(())
219 }
220
221 pub fn contains<'a>(&self, quad: impl Into<QuadRef<'a>>) -> Result<bool> {
223 let quad_ref = quad.into();
224 let quad = Quad::new(
225 quad_ref.subject().to_owned(),
226 quad_ref.predicate().to_owned(),
227 quad_ref.object().to_owned(),
228 quad_ref.graph_name().to_owned(),
229 );
230
231 let store = self
232 .inner
233 .read()
234 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
235 store.contains_quad(&quad)
236 }
237
238 pub fn len(&self) -> Result<usize> {
240 let store = self
241 .inner
242 .read()
243 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
244 store.len()
245 }
246
247 pub fn is_empty(&self) -> Result<bool> {
249 let store = self
250 .inner
251 .read()
252 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
253 store.is_empty()
254 }
255
256 pub fn quads_for_pattern<'a>(
258 &self,
259 subject: Option<impl Into<SubjectRef<'a>>>,
260 predicate: Option<impl Into<PredicateRef<'a>>>,
261 object: Option<impl Into<ObjectRef<'a>>>,
262 graph_name: Option<impl Into<GraphNameRef<'a>>>,
263 ) -> QuadIter {
264 let subject = subject.map(|s| {
265 let s_ref = s.into();
266 match s_ref {
267 SubjectRef::NamedNode(n) => Subject::NamedNode(n.to_owned()),
268 SubjectRef::BlankNode(b) => Subject::BlankNode(b.to_owned()),
269 SubjectRef::Variable(v) => Subject::Variable(v.to_owned()),
270 }
271 });
272
273 let predicate = predicate.map(|p| {
274 let p_ref = p.into();
275 match p_ref {
276 PredicateRef::NamedNode(n) => Predicate::NamedNode(n.to_owned()),
277 PredicateRef::Variable(v) => Predicate::Variable(v.to_owned()),
278 }
279 });
280
281 let object = object.map(|o| {
282 let o_ref = o.into();
283 match o_ref {
284 ObjectRef::NamedNode(n) => Object::NamedNode(n.to_owned()),
285 ObjectRef::BlankNode(b) => Object::BlankNode(b.to_owned()),
286 ObjectRef::Literal(l) => Object::Literal(l.to_owned()),
287 ObjectRef::Variable(v) => Object::Variable(v.to_owned()),
288 }
289 });
290
291 let graph_name = graph_name.map(|g| {
292 let g_ref = g.into();
293 g_ref.to_owned()
294 });
295
296 let quads = match self.inner.read() {
298 Ok(store) => store
299 .query_quads(
300 subject.as_ref(),
301 predicate.as_ref(),
302 object.as_ref(),
303 graph_name.as_ref(),
304 )
305 .unwrap_or_default(),
306 _ => Vec::new(),
307 };
308
309 QuadIter { quads, index: 0 }
310 }
311
312 pub fn iter(&self) -> QuadIter {
314 self.quads_for_pattern(
315 None::<SubjectRef>,
316 None::<PredicateRef>,
317 None::<ObjectRef>,
318 None::<GraphNameRef>,
319 )
320 }
321
322 pub fn named_graphs(&self) -> GraphNameIter {
324 let mut graph_names = std::collections::HashSet::new();
326 if let Ok(store) = self.inner.read() {
327 if let Ok(quads) = store.iter_quads() {
328 for quad in quads {
329 if let GraphName::NamedNode(n) = quad.graph_name() {
330 graph_names.insert(n.clone());
331 }
332 }
333 }
334 }
335
336 GraphNameIter {
337 graphs: graph_names.into_iter().collect(),
338 index: 0,
339 }
340 }
341
342 pub fn contains_named_graph<'a>(
344 &self,
345 graph_name: impl Into<NamedOrBlankNodeRef<'a>>,
346 ) -> Result<bool> {
347 let graph_ref = graph_name.into();
348 let graph = match graph_ref {
349 NamedOrBlankNodeRef::NamedNode(n) => GraphName::NamedNode(n.to_owned()),
350 NamedOrBlankNodeRef::BlankNode(b) => GraphName::BlankNode(b.to_owned()),
351 };
352
353 let store = self
355 .inner
356 .read()
357 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
358 let quads = store.query_quads(None, None, None, Some(&graph))?;
359 Ok(!quads.is_empty())
360 }
361
362 pub fn clear(&self) -> Result<()> {
364 let mut store = self
365 .inner
366 .write()
367 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
368 store.clear()
369 }
370
371 pub fn clear_graph<'a>(&self, graph_name: impl Into<GraphNameRef<'a>>) -> Result<()> {
373 let graph_ref = graph_name.into();
374 let graph = graph_ref.to_owned();
375
376 let store = self
377 .inner
378 .write()
379 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
380
381 let quads_to_remove = store.query_quads(None, None, None, Some(&graph))?;
383
384 for quad in quads_to_remove {
386 store.remove_quad(&quad)?;
387 }
388
389 Ok(())
390 }
391
392 pub fn query(&self, query: &str) -> Result<QueryResults> {
394 let store = self
395 .inner
396 .read()
397 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
398 let results = store.query(query)?;
399 Ok(QueryResults { inner: results })
400 }
401
402 pub fn update(&self, update_str: &str) -> Result<()> {
404 use crate::query::{UpdateExecutor, UpdateParser};
405
406 let parser = UpdateParser::new();
408 let update = parser.parse(update_str)?;
409
410 let store = self
412 .inner
413 .write()
414 .map_err(|e| OxirsError::Store(format!("Failed to acquire write lock: {e}")))?;
415
416 let executor = UpdateExecutor::new(&*store);
418 executor.execute(&update)?;
419
420 Ok(())
421 }
422
423 pub fn transaction<T, E>(
437 &self,
438 f: impl FnOnce(&mut crate::AcidTransaction) -> std::result::Result<T, E>,
439 ) -> std::result::Result<T, E>
440 where
441 E: From<OxirsError>,
442 {
443 self.ensure_tx_manager()?;
445
446 let mut tx_mgr_guard = self
448 .tx_manager
449 .write()
450 .map_err(|e| E::from(OxirsError::Store(format!("Failed to acquire lock: {e}"))))?;
451
452 let tx_mgr = tx_mgr_guard.as_mut().ok_or_else(|| {
453 E::from(OxirsError::Store(
454 "Transaction manager not initialized".to_string(),
455 ))
456 })?;
457
458 let mut transaction = tx_mgr.begin(IsolationLevel::Snapshot).map_err(E::from)?;
460
461 let result = f(&mut transaction);
463
464 match result {
466 Ok(value) => {
467 transaction.commit().map_err(E::from)?;
468 Ok(value)
469 }
470 Err(error) => {
471 let _ = transaction.abort();
472 Err(error)
473 }
474 }
475 }
476
477 fn ensure_tx_manager(&self) -> Result<()> {
479 let mut tx_mgr_guard = self
480 .tx_manager
481 .write()
482 .map_err(|e| OxirsError::Store(format!("Failed to acquire lock: {e}")))?;
483
484 if tx_mgr_guard.is_none() {
485 let wal_dir = if let Some(ref wal_path) = self.wal_dir {
487 wal_path.clone()
488 } else {
489 std::env::temp_dir().join("oxirs_wal")
491 };
492
493 let tx_mgr = TransactionManager::new(&wal_dir)?;
495 *tx_mgr_guard = Some(tx_mgr);
496 }
497
498 Ok(())
499 }
500
501 pub fn validate(&self) -> Result<()> {
503 Ok(())
505 }
506
507 pub fn optimize(&self) -> Result<()> {
509 let store = self
511 .inner
512 .read()
513 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
514 store.clear_arena();
515 Ok(())
516 }
517
518 pub fn backup<P: AsRef<Path>>(&self, path: P) -> Result<()> {
520 use crate::parser::RdfFormat;
521 use crate::serializer::Serializer;
522 use std::fs::File;
523 use std::io::Write;
524 use std::time::{SystemTime, UNIX_EPOCH};
525
526 let backup_path = path.as_ref();
527
528 if let Some(parent) = backup_path.parent() {
530 std::fs::create_dir_all(parent).map_err(|e| {
531 OxirsError::Store(format!("Failed to create backup directory: {e}"))
532 })?;
533 }
534
535 let timestamp = SystemTime::now()
537 .duration_since(UNIX_EPOCH)
538 .unwrap_or_default()
539 .as_secs();
540
541 let backup_file_path = if backup_path.is_dir() {
542 backup_path.join(format!("oxirs_backup_{timestamp}.nq"))
543 } else {
544 backup_path.to_path_buf()
545 };
546
547 let store = self
549 .inner
550 .read()
551 .map_err(|e| OxirsError::Store(format!("Failed to acquire read lock: {e}")))?;
552
553 let quads = store
555 .iter_quads()
556 .map_err(|e| OxirsError::Store(format!("Failed to iterate quads: {e}")))?;
557
558 let dataset = crate::model::dataset::Dataset::from_iter(quads.clone());
560
561 let serializer = Serializer::new(RdfFormat::NQuads);
563 let serialized_data = serializer
564 .serialize_dataset(&dataset)
565 .map_err(|e| OxirsError::Store(format!("Failed to serialize dataset: {e}")))?;
566
567 let mut backup_file = File::create(&backup_file_path)
569 .map_err(|e| OxirsError::Store(format!("Failed to create backup file: {e}")))?;
570
571 backup_file
572 .write_all(serialized_data.as_bytes())
573 .map_err(|e| OxirsError::Store(format!("Failed to write backup data: {e}")))?;
574
575 backup_file
576 .sync_all()
577 .map_err(|e| OxirsError::Store(format!("Failed to sync backup file: {e}")))?;
578
579 let backup_size = serialized_data.len();
581 let quad_count = quads.len();
582
583 tracing::info!(
584 "Store backup completed successfully. File: {}, Quads: {}, Size: {} bytes",
585 backup_file_path.display(),
586 quad_count,
587 backup_size
588 );
589
590 Ok(())
591 }
592
593 pub fn flush(&self) -> Result<()> {
595 Ok(())
597 }
598}
599
600impl Default for Store {
601 fn default() -> Self {
602 Store::new().expect("Store::new() should not fail")
603 }
604}
605
606pub struct QuadIter {
608 quads: Vec<Quad>,
609 index: usize,
610}
611
612impl Iterator for QuadIter {
613 type Item = Quad;
614
615 fn next(&mut self) -> Option<Self::Item> {
616 if self.index < self.quads.len() {
617 let quad = self.quads[self.index].clone();
618 self.index += 1;
619 Some(quad)
620 } else {
621 None
622 }
623 }
624}
625
626pub struct GraphNameIter {
628 graphs: Vec<NamedNode>,
629 index: usize,
630}
631
632impl Iterator for GraphNameIter {
633 type Item = NamedNode;
634
635 fn next(&mut self) -> Option<Self::Item> {
636 if self.index < self.graphs.len() {
637 let graph = self.graphs[self.index].clone();
638 self.index += 1;
639 Some(graph)
640 } else {
641 None
642 }
643 }
644}
645
646pub struct QueryResults {
648 #[allow(dead_code)]
649 inner: OxirsQueryResults,
650}
651
652impl QueryResults {
653 pub fn is_boolean(&self) -> bool {
655 matches!(
656 self.inner.results(),
657 crate::rdf_store::types::QueryResults::Boolean(_)
658 )
659 }
660
661 pub fn boolean(&self) -> Option<bool> {
663 match self.inner.results() {
664 crate::rdf_store::types::QueryResults::Boolean(b) => Some(*b),
665 _ => None,
666 }
667 }
668
669 pub fn is_solutions(&self) -> bool {
671 matches!(
672 self.inner.results(),
673 crate::rdf_store::types::QueryResults::Bindings(_)
674 )
675 }
676
677 pub fn is_graph(&self) -> bool {
679 matches!(
680 self.inner.results(),
681 crate::rdf_store::types::QueryResults::Graph(_)
682 )
683 }
684}
685
686pub struct Transaction {
691 operations: Vec<TransactionOp>,
693}
694
695enum TransactionOp {
696 #[allow(dead_code)]
697 Insert(Quad),
698 #[allow(dead_code)]
699 Remove(Quad),
700}
701
702impl Transaction {
703 #[allow(dead_code)]
704 fn new() -> Self {
705 Transaction {
706 operations: Vec::new(),
707 }
708 }
709
710 pub fn insert<'b>(&mut self, quad: impl Into<QuadRef<'b>>) -> Result<bool> {
712 let quad_ref = quad.into();
713 let quad = Quad::new(
714 quad_ref.subject().to_owned(),
715 quad_ref.predicate().to_owned(),
716 quad_ref.object().to_owned(),
717 quad_ref.graph_name().to_owned(),
718 );
719 self.operations.push(TransactionOp::Insert(quad));
720 Ok(true) }
722
723 pub fn remove<'b>(&mut self, quad: impl Into<QuadRef<'b>>) -> Result<bool> {
725 let quad_ref = quad.into();
726 let quad = Quad::new(
727 quad_ref.subject().to_owned(),
728 quad_ref.predicate().to_owned(),
729 quad_ref.object().to_owned(),
730 quad_ref.graph_name().to_owned(),
731 );
732 self.operations.push(TransactionOp::Remove(quad));
733 Ok(true) }
735}
736
737#[derive(Debug, thiserror::Error)]
739pub enum OxigraphCompatError {
740 #[error("Store error: {0}")]
741 Store(String),
742 #[error("Parse error: {0}")]
743 Parse(String),
744 #[error("IO error: {0}")]
745 Io(#[from] std::io::Error),
746}
747
748impl From<OxirsError> for OxigraphCompatError {
749 fn from(err: OxirsError) -> Self {
750 match err {
751 OxirsError::Store(msg) => OxigraphCompatError::Store(msg),
752 OxirsError::Parse(msg) => OxigraphCompatError::Parse(msg),
753 _ => OxigraphCompatError::Store(err.to_string()),
754 }
755 }
756}
757
758#[cfg(test)]
759mod tests {
760 use super::*;
761 use crate::model::{Literal, NamedNode};
762 use crate::parser::RdfFormat;
763 use std::io::Cursor;
764
765 #[test]
766 fn test_oxigraph_compat_store_creation() {
767 let store = Store::new().unwrap();
768 assert!(store.is_empty().unwrap());
769 assert_eq!(store.len().unwrap(), 0);
770 }
771
772 #[test]
773 fn test_oxigraph_compat_insert_and_query() {
774 let store = Store::new().unwrap();
775
776 let subject = NamedNode::new("http://example.org/subject").unwrap();
778 let predicate = NamedNode::new("http://example.org/predicate").unwrap();
779 let object = Literal::new("test object");
780 let graph = NamedNode::new("http://example.org/graph").unwrap();
781
782 let quad = Quad::new(
783 subject.clone(),
784 predicate.clone(),
785 object.clone(),
786 graph.clone(),
787 );
788
789 assert!(store.insert(QuadRef::from(&quad)).unwrap());
791 assert_eq!(store.len().unwrap(), 1);
792 assert!(!store.is_empty().unwrap());
793
794 assert!(store.contains(QuadRef::from(&quad)).unwrap());
796
797 let quads: Vec<_> = store
799 .quads_for_pattern(
800 Some(SubjectRef::NamedNode(&subject)),
801 None::<PredicateRef>,
802 None::<ObjectRef>,
803 None::<GraphNameRef>,
804 )
805 .collect();
806 assert_eq!(quads.len(), 1);
807 assert_eq!(quads[0], quad);
808
809 assert!(store.remove(QuadRef::from(&quad)).unwrap());
811 assert!(store.is_empty().unwrap());
812 }
813
814 #[test]
815 fn test_oxigraph_compat_extend() {
816 let store = Store::new().unwrap();
817
818 let quads = [
819 Quad::new(
820 NamedNode::new("http://example.org/s1").unwrap(),
821 NamedNode::new("http://example.org/p1").unwrap(),
822 Literal::new("o1"),
823 GraphName::DefaultGraph,
824 ),
825 Quad::new(
826 NamedNode::new("http://example.org/s2").unwrap(),
827 NamedNode::new("http://example.org/p2").unwrap(),
828 Literal::new("o2"),
829 NamedNode::new("http://example.org/g1").unwrap(),
830 ),
831 ];
832
833 store.extend(quads.iter().map(QuadRef::from)).unwrap();
834 assert_eq!(store.len().unwrap(), 2);
835 }
836
837 #[test]
838 fn test_oxigraph_compat_named_graphs() {
839 let store = Store::new().unwrap();
840
841 let s1 = NamedNode::new("http://example.org/s1").unwrap();
843 let s2 = NamedNode::new("http://example.org/s2").unwrap();
844 let p1 = NamedNode::new("http://example.org/p1").unwrap();
845 let p2 = NamedNode::new("http://example.org/p2").unwrap();
846 let o1 = Literal::new("o1");
847 let o2 = Literal::new("o2");
848 let g1 = NamedNode::new("http://example.org/g1").unwrap();
849 let g2 = NamedNode::new("http://example.org/g2").unwrap();
850
851 store
853 .insert(QuadRef::new(
854 SubjectRef::NamedNode(&s1),
855 PredicateRef::NamedNode(&p1),
856 ObjectRef::Literal(&o1),
857 GraphNameRef::NamedNode(&g1),
858 ))
859 .unwrap();
860
861 store
862 .insert(QuadRef::new(
863 SubjectRef::NamedNode(&s2),
864 PredicateRef::NamedNode(&p2),
865 ObjectRef::Literal(&o2),
866 GraphNameRef::NamedNode(&g2),
867 ))
868 .unwrap();
869
870 let graphs: Vec<_> = store.named_graphs().collect();
872 assert_eq!(graphs.len(), 2);
873 assert!(graphs.contains(&g1));
874 assert!(graphs.contains(&g2));
875
876 assert!(store
878 .contains_named_graph(NamedOrBlankNodeRef::NamedNode(&g1))
879 .unwrap());
880 assert!(store
881 .contains_named_graph(NamedOrBlankNodeRef::NamedNode(&g2))
882 .unwrap());
883 }
884
885 #[test]
886 fn test_oxigraph_compat_clear_graph() {
887 let store = Store::new().unwrap();
888
889 let s1 = NamedNode::new("http://example.org/s1").unwrap();
891 let s2 = NamedNode::new("http://example.org/s2").unwrap();
892 let p1 = NamedNode::new("http://example.org/p1").unwrap();
893 let p2 = NamedNode::new("http://example.org/p2").unwrap();
894 let o1 = Literal::new("o1");
895 let o2 = Literal::new("o2");
896 let graph = NamedNode::new("http://example.org/graph").unwrap();
897
898 store
900 .insert(QuadRef::new(
901 SubjectRef::NamedNode(&s1),
902 PredicateRef::NamedNode(&p1),
903 ObjectRef::Literal(&o1),
904 GraphNameRef::NamedNode(&graph),
905 ))
906 .unwrap();
907
908 store
909 .insert(QuadRef::new(
910 SubjectRef::NamedNode(&s2),
911 PredicateRef::NamedNode(&p2),
912 ObjectRef::Literal(&o2),
913 GraphNameRef::DefaultGraph,
914 ))
915 .unwrap();
916
917 assert_eq!(store.len().unwrap(), 2);
918
919 store.clear_graph(GraphNameRef::NamedNode(&graph)).unwrap();
921 assert_eq!(store.len().unwrap(), 1); store.clear().unwrap();
925 assert!(store.is_empty().unwrap());
926 }
927
928 #[test]
929 fn test_oxigraph_compat_load_from_reader() {
930 let store = Store::new().unwrap();
931
932 let turtle_data = r#"
933 @prefix ex: <http://example.org/> .
934 ex:subject ex:predicate "object" .
935 "#;
936
937 let reader = Cursor::new(turtle_data.as_bytes());
938 store
939 .load_from_reader(
940 reader,
941 RdfFormat::Turtle,
942 Some("http://example.org/"),
943 None::<GraphName>,
944 )
945 .unwrap();
946
947 assert_eq!(store.len().unwrap(), 1);
948
949 let quads: Vec<_> = store.iter().collect();
951 assert_eq!(quads.len(), 1);
952 assert_eq!(
953 quads[0].subject().to_string(),
954 "<http://example.org/subject>"
955 );
956 assert_eq!(
957 quads[0].predicate().to_string(),
958 "<http://example.org/predicate>"
959 );
960 }
961
962 #[test]
963 fn test_oxigraph_compat_dump_to_writer() {
964 let store = Store::new().unwrap();
965
966 let subject = NamedNode::new("http://example.org/subject").unwrap();
968 let predicate = NamedNode::new("http://example.org/predicate").unwrap();
969 let object = Literal::new("object");
970
971 store
973 .insert(QuadRef::new(
974 SubjectRef::NamedNode(&subject),
975 PredicateRef::NamedNode(&predicate),
976 ObjectRef::Literal(&object),
977 GraphNameRef::DefaultGraph,
978 ))
979 .unwrap();
980
981 let mut output = Vec::new();
983 store
984 .dump_to_writer(&mut output, RdfFormat::NTriples, None::<GraphNameRef>)
985 .unwrap();
986
987 let result = String::from_utf8(output).unwrap();
988 assert!(result.contains("<http://example.org/subject>"));
989 assert!(result.contains("<http://example.org/predicate>"));
990 assert!(result.contains("\"object\""));
991 }
992}