7 #include "knowrob/semweb/SPARQLQuery.h"
8 #include "knowrob/terms/Atom.h"
9 #include "knowrob/semweb/GraphSequence.h"
10 #include "knowrob/semweb/PrefixRegistry.h"
11 #include "knowrob/semweb/Resource.h"
16 : flags_(flags), varCounter_(0) {
17 std::stringstream os, os_query;
19 add(os_query, triplePattern);
28 : flags_(flags), varCounter_(0) {
29 std::stringstream os_query;
30 add(os_query, query->term());
45 for (
const auto &[alias, uri]:
aliases_) {
46 os <<
"PREFIX " << alias <<
": <" << uri <<
"#>\n";
54 auto sequence = std::static_pointer_cast<GraphSequence>(
graphTerm);
56 for (
const auto &
term: sequence->terms()) {
70 auto sequence = std::static_pointer_cast<GraphSequence>(
graphTerm);
71 for (
const auto &
term: sequence->terms()) {
77 add(os, *std::static_pointer_cast<GraphPattern>(
graphTerm)->value());
80 add(os, *std::static_pointer_cast<GraphBuiltin>(
graphTerm));
120 if (builtin.
arguments()[0]->isVariable()) {
121 os <<
"!BOUND(?" << std::static_pointer_cast<Variable>(builtin.
arguments()[0])->name() <<
") || ";
123 if (builtin.
arguments()[1]->isVariable()) {
124 os <<
"!BOUND(?" << std::static_pointer_cast<Variable>(builtin.
arguments()[1])->name() <<
") || ";
129 os << comparisonOperator <<
' ';
137 os <<
" BIND ( IF( (";
138 if (builtin.
arguments()[1]->isVariable()) {
139 os <<
"BOUND(?" << std::static_pointer_cast<Variable>(builtin.
arguments()[1])->name() <<
") && ";
144 os <<
' ' << comparisonOperator <<
' ';
151 os <<
") AS ?" << builtin.
bindVar()->name() <<
")\n";
177 os <<
"AS ?" << builtin.
bindVar()->name();
195 os <<
'?' <<
var <<
' ';
207 if (!
term->isAtomic())
return;
209 os <<
" !BOUND(?" << varName <<
") || ";
210 doFilter(os, varName, std::static_pointer_cast<Atomic>(
term), operatorType);
215 if (!
term->isAtomic())
return;
216 auto atomic = std::static_pointer_cast<Atomic>(
term);
218 doFilter(os, varName, std::static_pointer_cast<Atomic>(
term), operatorType);
223 os <<
'?' << varName;
224 switch (operatorType) {
244 if (
atomic->isNumeric()) {
245 os <<
'"' << *
atomic <<
'"' <<
"^^";
248 else if (
atomic->isString()) {
252 os <<
atomic->stringForm();
258 os <<
"FILTER NOT EXISTS { ";
264 if (triplePattern.
objectTerm()->isVariable()) {
265 bool hasObjectOperator =
optional(os, triplePattern);
267 if (hasObjectOperator) {
278 KB_WARN(
"Negation via optional is only supported for variable objects.");
284 bool needsFilter =
where(os, triplePattern);
291 bool hasAlias =
false;
294 if (alias.has_value()) {
295 auto &v_alias = alias.value().get();
302 os << '<' << iri << '>
';
307 void SPARQLQuery::where_with_filter(std::ostream &os, const TriplePattern &triplePattern) {
308 if (where(os, triplePattern)) {
309 filter(os, lastVar_, triplePattern.objectTerm(), triplePattern.objectOperator());
313 bool SPARQLQuery::where(std::ostream &os, const TriplePattern &triplePattern) {
314 where(os, triplePattern.subjectTerm());
315 where(os, triplePattern.propertyTerm());
316 if (triplePattern.objectTerm()->isVariable() || triplePattern.objectOperator() == FilterType::EQ) {
317 if (!triplePattern.objectTerm()->isVariable() && triplePattern.objectVariable()) {
318 where(os, triplePattern.objectVariable());
320 lastVar_ = triplePattern.objectVariable()->name();
323 where(os, triplePattern.objectTerm());
327 } else if (triplePattern.objectVariable()) {
328 // value, operator and variable are provided in the pattern
329 lastVar_ = triplePattern.objectVariable()->name();
330 variables_.insert(triplePattern.objectVariable()->name());
331 os << "?" << lastVar_ << " . ";
334 // we need to introduce a temporary variable to handle value expressions like `<(5)` such
335 // that they can be filtered after the match.
336 static const std::string adhocVarPrefix = "v_adhoc";
337 std::stringstream varName_os;
338 varName_os << adhocVarPrefix << (varCounter_++);
339 lastVar_ = varName_os.str();
340 os << "?" << lastVar_ << " . ";
345 void SPARQLQuery::where(std::ostream &os, const TermPtr &term) {
346 switch (term->termType()) {
347 case TermType::VARIABLE: {
348 auto var = std::static_pointer_cast<Variable>(term);
349 variables_.insert(var->name());
350 os << "?" << var->name() << " ";
353 case TermType::ATOMIC: {
355 iri(os, std::static_pointer_cast<Atomic>(term)->stringForm());
357 } else if (term->isBlank()) {
358 os << "_:" << std::static_pointer_cast<Atomic>(term)->stringForm() << " ";
364 if (term->isNumeric() || term->isString()) {
365 auto xsdAtomic = std::static_pointer_cast<XSDAtomic>(term);
366 if (xsdAtomic->xsdType() == XSDType::BOOLEAN) {
367 auto numeric = std::static_pointer_cast<Numeric>(term);
368 os << (numeric->asBoolean() ? "\"true\"" : "\"false\"");
369 } else if (xsdAtomic->isString()) {
372 os << '"' << *term << '"';
375 iri(os, xsdTypeToIRI(xsdAtomic->xsdType()));
377 } else if (term->termType() == TermType::ATOMIC) {
378 // handle the case that an IRI was not handed in as an IRIAtom
379 iri(os, std::static_pointer_cast<Atomic>(term)->stringForm());
381 KB_WARN("Invalid term `{}` in SPARQL query.", *term);
387 SPARQLFlag knowrob::operator|(SPARQLFlag a, SPARQLFlag b) {
388 return static_cast<SPARQLFlag>(static_cast<std::uint8_t>(a) | static_cast<std::uint8_t>(b));
391 bool knowrob::operator&(SPARQLFlag a, SPARQLFlag b) {
392 return static_cast<std::uint8_t>(a) & static_cast<std::uint8_t>(b);
static OptionalStringRef uriToAlias(std::string_view uri)
void comparison(std::ostream &os, const GraphBuiltin &builtin, const char *comparisonOperator)
bool optional(std::ostream &os, const TriplePattern &triplePattern)
std::map< std::string_view, std::string_view > aliases_
void filter(std::ostream &os, std::string_view varName, const TermPtr &term, FilterType operatorType)
void bindOneOfIf(std::ostream &os, const GraphBuiltin &builtin, const char *comparisonOperator)
void doFilter(std::ostream &os, std::string_view varName, const std::shared_ptr< Atomic > &atomic, FilterType operatorType)
void selectBegin(std::ostream &os)
SPARQLQuery(const TriplePattern &triplePattern, SPARQLFlags flags=SPARQLFlag::NOTHING)
void where_with_filter(std::ostream &os, const TriplePattern &triplePattern)
void iri(std::ostream &os, std::string_view iri)
std::set< std::string_view > variables_
void appendPrefixes(std::ostream &os)
bool where(std::ostream &os, const TriplePattern &triplePattern)
void negationViaNotExists(std::ostream &os, const TriplePattern &triplePattern)
static void selectEnd(std::ostream &os)
void filter_optional(std::ostream &os, std::string_view varName, const TermPtr &term, FilterType operatorType)
void add(std::ostream &os, const TriplePattern &triplePattern)
void negationViaOptional(std::ostream &os, const TriplePattern &triplePattern)
auto objectOperator() const
auto & objectTerm() const
static std::string_view iri_name(std::string_view iri)
static std::string_view iri_ns(std::string_view iri, bool includeDelimiter=false)
GraphTermRule & graphTerm()
std::string_view xsdTypeToIRI(XSDType type)
@ QUERY_FLAG_ONE_SOLUTION
std::shared_ptr< Term > TermPtr
FilterType inverseFilterType(FilterType op)
IRIAtomPtr iri(std::string_view ns, std::string_view name)