use rudf::model::*; use rudf::{GraphSyntax, Repository, RepositoryConnection, MemoryRepository, Result}; use rudf::sparql::{BindingsIterator, GraphPattern, PreparedQuery, QueryOptions, QueryResult, ServiceHandler}; use failure::format_err; use std::io::BufRead; #[test] fn simple_service_test() { struct TestServiceHandler; impl ServiceHandler for TestServiceHandler { fn handle<'a>(&'a self, _named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result>)> { fn pattern_handler<'a>(graph_pattern: GraphPattern) -> Result> { let triples = b" .".as_ref(); do_pattern(triples, graph_pattern, QueryOptions::default()) }; Some(pattern_handler) } } let query = r#" SELECT ?s ?p ?o WHERE { SERVICE { ?s ?p ?o } } "#.to_string(); let options = QueryOptions::default().with_service_handler(Box::new(TestServiceHandler)); let results = do_query(b"".as_ref(), query, options).unwrap(); let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::>(); let solution = vec![ vec![ Some(ex(String::from("s"))), Some(ex(String::from("p"))), Some(ex(String::from("o"))) ], ]; assert_eq!(collected, solution); } #[test] fn two_service_test() { #[derive(Clone,Copy)] struct TwoServiceTest; impl ServiceHandler for TwoServiceTest { fn handle<'a>(&'a self, named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result>)> { let service1 = NamedNode::parse("http://service1.org").unwrap(); let service2 = NamedNode::parse("http://service2.org").unwrap(); if named_node == service1 { Some(TwoServiceTest::handle_service1) } else if named_node == service2 { Some(TwoServiceTest::handle_service2) } else { None } } } impl TwoServiceTest { fn handle_service1<'a>(graph_pattern: GraphPattern) -> Result> { let triples = br#" "Bob" . "Alice" . "#.as_ref(); do_pattern(triples, graph_pattern, QueryOptions::default()) } fn handle_service2<'a>(graph_pattern: GraphPattern) -> Result> { let triples = br#" . . "#.as_ref(); do_pattern(triples, graph_pattern, QueryOptions::default()) } } let query = r#" PREFIX foaf: SELECT ?name ?mbox WHERE { SERVICE { ?s foaf:name ?name } SERVICE { ?s foaf:mbox ?mbox } } ORDER BY ?name "#.to_string(); let options = QueryOptions::default().with_service_handler(Box::new(TwoServiceTest)); let results = do_query(b"".as_ref(), query, options).unwrap(); let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::>(); let solution = vec![ vec![ Some(literal("Alice".to_string())), Some(mailto("alice@example.com".to_string())) ], vec![ Some(literal("Bob".to_string())), Some(mailto("bob@example.com".to_string())) ], ]; assert_eq!(collected, solution); } #[test] fn silent_service_empty_set_test() { #[derive(Clone,Copy)] struct ServiceTest; impl ServiceHandler for ServiceTest { fn handle<'a>(&'a self, _named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result>)> { Some(ServiceTest::handle_service) } } impl ServiceTest { fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result> { Err(format_err!("This is supposed to fail")) } } let query = r#" PREFIX foaf: SELECT ?name ?mbox WHERE { SERVICE SILENT { ?s foaf:name ?name } } ORDER BY ?name "#.to_string(); let triples = b"".as_ref(); let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest)); let results = do_query(triples, query, options).unwrap(); let collected = results.into_values_iter().map(move |b| b.unwrap()).collect::>(); println!("Collected: {:?}", collected); assert_eq!(collected.len(), 0); } #[test] fn non_silent_service_test() { #[derive(Clone,Copy)] struct ServiceTest; impl ServiceHandler for ServiceTest { fn handle<'a>(&'a self, _named_node: NamedNode) -> Option<(fn(GraphPattern) -> Result>)> { Some(ServiceTest::handle_service) } } impl ServiceTest { fn handle_service<'a>(_graph_pattern: GraphPattern) -> Result> { Err(format_err!("This is supposed to fail")) } } let query = r#" PREFIX foaf: SELECT ?name WHERE { SERVICE { ?s foaf:name ?name } } ORDER BY ?name "#.to_string(); let triples = b"".as_ref(); let options = QueryOptions::default().with_service_handler(Box::new(ServiceTest)); let results = do_query(triples, query, options).unwrap(); let result = results.into_values_iter().next(); match result { Some(Err(_)) => assert_eq!(true, true), _ => assert_eq!(true, false, "This should have been an error since the service fails"), } } fn ex(id: String) -> Term { Term::NamedNode(NamedNode::parse(format!("http://example.com/{}", &id)).unwrap()) } fn mailto(id: String) -> Term { Term::NamedNode(NamedNode::parse(format!("mailto:{}", &id)).unwrap()) } fn literal(str: String) -> Term { Term::Literal(Literal::new_simple_literal(str)) } fn make_repository(reader: impl BufRead) -> Result { let repository = MemoryRepository::default(); let mut connection = repository.connection()?; connection.load_graph(reader, GraphSyntax::NTriples, None, None).unwrap(); Ok(repository) } fn query_repository<'a>(repository: MemoryRepository, query: String, options: QueryOptions<'a>) -> Result> { let connection = repository.connection()?; let prepared_query = connection.prepare_query(&query, None)?; let result = prepared_query.exec(&options)?; match result { QueryResult::Bindings(iterator) => { let (varaibles, iter) = iterator.destruct(); let collected = iter.collect::>(); Ok(BindingsIterator::new(varaibles, Box::new(collected.into_iter()))) }, _ => Err(format_err!("Excpected bindings but got another QueryResult")) } } fn pattern_repository<'a>(repository: MemoryRepository, pattern: GraphPattern, options: QueryOptions<'a>) -> Result> { let connection = repository.connection()?; let prepared_query = connection.prepare_query_from_pattern(&pattern, None)?; let result = prepared_query.exec(&options)?; match result { QueryResult::Bindings(iterator) => { let (varaibles, iter) = iterator.destruct(); let collected = iter.collect::>(); Ok(BindingsIterator::new(varaibles, Box::new(collected.into_iter()))) } _ => Err(format_err!("Excpected bindings but got another QueryResult")) } } fn do_query<'a>(reader: impl BufRead, query: String, options: QueryOptions<'a>) -> Result> { let repository = make_repository(reader)?; query_repository(repository, query, options) } fn do_pattern<'a>(reader: impl BufRead, pattern: GraphPattern, options: QueryOptions<'a>) -> Result> { let repository = make_repository(reader)?; pattern_repository(repository, pattern, options) }