diff --git a/src/parser/ParsedQuery.h b/src/parser/ParsedQuery.h index 2b8dd8320c..4201a3c783 100644 --- a/src/parser/ParsedQuery.h +++ b/src/parser/ParsedQuery.h @@ -18,6 +18,7 @@ #include "parser/PropertyPath.h" #include "parser/SelectClause.h" #include "parser/TripleComponent.h" +#include "parser/UpdateClause.h" #include "parser/data/GroupKey.h" #include "parser/data/LimitOffsetClause.h" #include "parser/data/OrderKey.h" @@ -49,75 +50,8 @@ class SparqlPrefix { bool operator==(const SparqlPrefix&) const = default; }; -inline bool isVariable(const string& elem) { return elem.starts_with("?"); } -inline bool isVariable(const TripleComponent& elem) { - return elem.isVariable(); -} - -inline bool isVariable(const PropertyPath& elem) { - return elem._operation == PropertyPath::Operation::IRI && - isVariable(elem._iri); -} - std::ostream& operator<<(std::ostream& out, const PropertyPath& p); -// Data container for parsed triples from the where clause. -// It is templated on the predicate type, see the instantiations below. -template -class SparqlTripleBase { - public: - using AdditionalScanColumns = std::vector>; - SparqlTripleBase(TripleComponent s, Predicate p, TripleComponent o, - AdditionalScanColumns additionalScanColumns = {}) - : s_(std::move(s)), - p_(std::move(p)), - o_(std::move(o)), - additionalScanColumns_(std::move(additionalScanColumns)) {} - - bool operator==(const SparqlTripleBase& other) const = default; - TripleComponent s_; - Predicate p_; - TripleComponent o_; - // The additional columns (e.g. patterns) that are to be attached when - // performing an index scan using this triple. - // TODO On this level we should not store `ColumnIndex`, but the - // special predicate IRIs that are to be attached here. - std::vector> additionalScanColumns_; -}; - -// A triple where the predicate is a `TripleComponent`, so a fixed entity or a -// variable, but not a property path. -class SparqlTripleSimple : public SparqlTripleBase { - using Base = SparqlTripleBase; - using Base::Base; -}; - -// A triple where the predicate is a `PropertyPath` (which technically still -// might be a variable or fixed entity in the current implementation). -class SparqlTriple : public SparqlTripleBase { - public: - using Base = SparqlTripleBase; - using Base::Base; - - // ___________________________________________________________________________ - SparqlTriple(TripleComponent s, const std::string& p_iri, TripleComponent o) - : Base{std::move(s), PropertyPath::fromIri(p_iri), std::move(o)} {} - - // ___________________________________________________________________________ - [[nodiscard]] string asString() const; - - // Convert to a simple triple. Fails with an exception if the predicate - // actually is a property path. - SparqlTripleSimple getSimple() const { - AD_CONTRACT_CHECK(p_.isIri()); - TripleComponent p = - isVariable(p_._iri) - ? TripleComponent{Variable{p_._iri}} - : TripleComponent(TripleComponent::Iri::fromIriref(p_._iri)); - return {s_, p, o_, additionalScanColumns_}; - } -}; - // Forward declaration namespace parsedQuery { struct GraphPatternOperation; @@ -132,6 +66,8 @@ class ParsedQuery { using ConstructClause = parsedQuery::ConstructClause; + using UpdateClause = parsedQuery::UpdateClause; + ParsedQuery() = default; GraphPattern _rootGraphPattern; @@ -147,7 +83,8 @@ class ParsedQuery { // explicit default initialisation because the constructor // of SelectClause is private - std::variant _clause{SelectClause{}}; + std::variant _clause{ + SelectClause{}}; [[nodiscard]] bool hasSelectClause() const { return std::holds_alternative(_clause); @@ -157,6 +94,10 @@ class ParsedQuery { return std::holds_alternative(_clause); } + [[nodiscard]] bool hasUpdateClause() const { + return std::holds_alternative(_clause); + } + [[nodiscard]] decltype(auto) selectClause() const { return std::get(_clause); } @@ -165,6 +106,10 @@ class ParsedQuery { return std::get(_clause); } + [[nodiscard]] decltype(auto) updateClause() const { + return std::get(_clause); + } + [[nodiscard]] decltype(auto) selectClause() { return std::get(_clause); } @@ -173,6 +118,10 @@ class ParsedQuery { return std::get(_clause); } + [[nodiscard]] decltype(auto) updateClause() { + return std::get(_clause); + } + // Add a variable, that was found in the query body. void registerVariableVisibleInQueryBody(const Variable& variable); diff --git a/src/parser/SparqlTriple.h b/src/parser/SparqlTriple.h new file mode 100644 index 0000000000..0efe19b8bd --- /dev/null +++ b/src/parser/SparqlTriple.h @@ -0,0 +1,91 @@ +// Copyright 2024, University of Freiburg, +// Chair of Algorithms and Data Structures. +// Authors: Björn Buchhold (buchhold@informatik.uni-freiburg.de) +// Johannes Kalmbach + +#pragma once + +#include + +#include "PropertyPath.h" +#include "TripleComponent.h" +#include "global/Id.h" +#include "parser/data/Variable.h" + +inline bool isVariable(const string& elem) { return elem.starts_with("?"); } +inline bool isVariable(const TripleComponent& elem) { + return elem.isVariable(); +} + +inline bool isVariable(const PropertyPath& elem) { + return elem._operation == PropertyPath::Operation::IRI && + isVariable(elem._iri); +} + +// Data container for parsed triples from the where clause. +// It is templated on the predicate type, see the instantiations below. +template +class SparqlTripleBase { + public: + using AdditionalScanColumns = std::vector>; + SparqlTripleBase(TripleComponent s, Predicate p, TripleComponent o, + AdditionalScanColumns additionalScanColumns = {}) + : s_(std::move(s)), + p_(std::move(p)), + o_(std::move(o)), + additionalScanColumns_(std::move(additionalScanColumns)) {} + + bool operator==(const SparqlTripleBase& other) const = default; + TripleComponent s_; + Predicate p_; + TripleComponent o_; + // The additional columns (e.g. patterns) that are to be attached when + // performing an index scan using this triple. + // TODO On this level we should not store `ColumnIndex`, but the + // special predicate IRIs that are to be attached here. + std::vector> additionalScanColumns_; +}; + +// A triple where the predicate is a `TripleComponent`, so a fixed entity or a +// variable, but not a property path. +class SparqlTripleSimple : public SparqlTripleBase { + using Base = SparqlTripleBase; + using Base::Base; +}; + +// A triple where the predicate is a `PropertyPath` (which technically still +// might be a variable or fixed entity in the current implementation). +class SparqlTriple : public SparqlTripleBase { + public: + using Base = SparqlTripleBase; + using Base::Base; + + // ___________________________________________________________________________ + SparqlTriple(TripleComponent s, const std::string& iri, TripleComponent o) + : Base{std::move(s), PropertyPath::fromIri(iri), std::move(o)} {} + + // ___________________________________________________________________________ + [[nodiscard]] string asString() const; + + // Convert to a simple triple. Fails with an exception if the predicate + // actually is a property path. + SparqlTripleSimple getSimple() const { + AD_CONTRACT_CHECK(p_.isIri()); + TripleComponent p = + isVariable(p_._iri) + ? TripleComponent{Variable{p_._iri}} + : TripleComponent(TripleComponent::Iri::fromIriref(p_._iri)); + return {s_, p, o_, additionalScanColumns_}; + } + + // Constructs SparqlTriple from a simple triple. Fails with an exception if + // the predicate is neither a variable nor an iri. + static SparqlTriple fromSimple(const SparqlTripleSimple& triple) { + AD_CONTRACT_CHECK(triple.p_.isVariable() || triple.p_.isIri()); + PropertyPath p = triple.p_.isVariable() + ? PropertyPath::fromVariable(triple.p_.getVariable()) + : PropertyPath::fromIri( + triple.p_.getIri().toStringRepresentation()); + return {triple.s_, p, triple.o_}; + } +}; diff --git a/src/parser/UpdateClause.h b/src/parser/UpdateClause.h new file mode 100644 index 0000000000..85f79bc046 --- /dev/null +++ b/src/parser/UpdateClause.h @@ -0,0 +1,21 @@ +// Copyright 2024, University of Freiburg, +// Chair of Algorithms and Data Structures. +// Author: Julian Mundhahs (mundhahj@informatik.uni-freiburg.de) + +#pragma once + +#include "parser/SelectClause.h" +#include "parser/SparqlTriple.h" +#include "parser/data/Types.h" + +namespace parsedQuery { +struct UpdateClause : ClauseBase { + std::vector toInsert_; + std::vector toDelete_; + + UpdateClause() = default; + UpdateClause(std::vector toInsert, + std::vector toDelete) + : toInsert_{std::move(toInsert)}, toDelete_{std::move(toDelete)} {} +}; +} // namespace parsedQuery diff --git a/src/parser/data/GraphRef.h b/src/parser/data/GraphRef.h new file mode 100644 index 0000000000..fff4f19bee --- /dev/null +++ b/src/parser/data/GraphRef.h @@ -0,0 +1,17 @@ +// Copyright 2024, University of Freiburg, +// Chair of Algorithms and Data Structures. +// Author: Julian Mundhahs (mundhahj@informatik.uni-freiburg.de) + +#pragma once + +#include + +#include "parser/Iri.h" + +using GraphRef = TripleComponent::Iri; +struct DEFAULT {}; +struct NAMED {}; +struct ALL {}; + +using GraphRefAll = std::variant; +using GraphOrDefault = std::variant; diff --git a/src/parser/sparqlParser/SparqlQleverVisitor.cpp b/src/parser/sparqlParser/SparqlQleverVisitor.cpp index d11e17631a..14f469f973 100644 --- a/src/parser/sparqlParser/SparqlQleverVisitor.cpp +++ b/src/parser/sparqlParser/SparqlQleverVisitor.cpp @@ -325,6 +325,230 @@ std::optional Visitor::visit(Parser::ValuesClauseContext* ctx) { return visitOptional(ctx->dataBlock()); } +// ____________________________________________________________________________________ +ParsedQuery Visitor::visit(Parser::UpdateContext* ctx) { + visit(ctx->prologue()); + + auto query = visit(ctx->update1()); + + if (ctx->update()) { + parsedQuery_ = ParsedQuery{}; + reportNotSupported(ctx->update(), "Multiple updates in one query are"); + } + + return query; +} + +// ____________________________________________________________________________________ +ParsedQuery Visitor::visit(Parser::Update1Context* ctx) { + if (ctx->modify()) { + return visit(ctx->modify()); + } else if (ctx->clear()) { + return visit(ctx->clear()); + } + + parsedQuery_._clause = parsedQuery::UpdateClause(); + + if (ctx->insertData() || ctx->deleteData()) { + // handles insertData and deleteData cases + visitIf(&parsedQuery_.updateClause().toInsert_, ctx->insertData()); + visitIf(&parsedQuery_.updateClause().toDelete_, ctx->deleteData()); + } else if (ctx->deleteWhere()) { + auto [toDelete, pattern] = visit(ctx->deleteWhere()); + parsedQuery_.updateClause().toDelete_ = std::move(toDelete); + parsedQuery_._rootGraphPattern = std::move(pattern); + } else { + visitAlternative(ctx->load(), ctx->drop(), ctx->add(), ctx->move(), + ctx->copy(), ctx->create()); + AD_FAIL(); + } + + return parsedQuery_; +} + +// ____________________________________________________________________________________ +void Visitor::visit(const Parser::LoadContext* ctx) const { + reportNotSupported(ctx, "SPARQL 1.1 Update Load is"); +} + +// ____________________________________________________________________________________ +ParsedQuery Visitor::visit(Parser::ClearContext* ctx) { + auto graphRef = visit(ctx->graphRefAll()); + + if (holds_alternative(graphRef)) { + parsedQuery_._clause = parsedQuery::UpdateClause(); + parsedQuery_.updateClause().toDelete_ = { + {Variable("?s"), Variable("?p"), Variable("?o")}}; + parsedQuery_._rootGraphPattern._graphPatterns.emplace_back( + BasicGraphPattern{{{Variable("?s"), "?p", Variable("?o")}}}); + return parsedQuery_; + } else { + reportNotSupported(ctx, "Named Graphs are"); + } +} + +// ____________________________________________________________________________________ +void Visitor::visit(const Parser::DropContext* ctx) const { + reportNotSupported(ctx, "SPARQL 1.1 Update Drop is"); +} + +// ____________________________________________________________________________________ +void Visitor::visit(const Parser::CreateContext* ctx) const { + reportNotSupported(ctx, "SPARQL 1.1 Update Create is"); +} + +// ____________________________________________________________________________________ +void Visitor::visit(const Parser::AddContext* ctx) const { + reportNotSupported(ctx, "SPARQL 1.1 Update Add is"); +} + +// ____________________________________________________________________________________ +void Visitor::visit(const Parser::MoveContext* ctx) const { + reportNotSupported(ctx, "SPARQL 1.1 Update Move is"); +} + +// ____________________________________________________________________________________ +void Visitor::visit(const Parser::CopyContext* ctx) const { + reportNotSupported(ctx, "SPARQL 1.1 Update Copy is"); +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::InsertDataContext* ctx) { + return visit(ctx->quadData()); +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::DeleteDataContext* ctx) { + return visit(ctx->quadData()); +} + +// ____________________________________________________________________________________ +std::pair, ParsedQuery::GraphPattern> Visitor::visit( + Parser::DeleteWhereContext* ctx) { + auto triples = visit(ctx->quadPattern()); + auto registerIfVariable = [this](const TripleComponent& component) { + if (component.isVariable()) { + addVisibleVariable(component.getVariable()); + } + }; + auto transformAndRegisterTriple = + [registerIfVariable](const SparqlTripleSimple& triple) { + registerIfVariable(triple.s_); + registerIfVariable(triple.p_); + registerIfVariable(triple.o_); + + // The predicate comes from a rule in the grammar (`verb`) which only + // allows variables and IRIs. + AD_CORRECTNESS_CHECK(triple.p_.isVariable() || triple.p_.isIri()); + return SparqlTriple::fromSimple(triple); + }; + GraphPattern pattern; + pattern._graphPatterns.emplace_back(BasicGraphPattern{ + ad_utility::transform(triples, transformAndRegisterTriple)}); + + return {std::move(triples), std::move(pattern)}; +} + +// ____________________________________________________________________________________ +ParsedQuery Visitor::visit(Parser::ModifyContext* ctx) { + if (ctx->iri()) { + reportNotSupported(ctx->iri(), "Named graphs are"); + } + if (!ctx->usingClause().empty()) { + reportNotSupported(ctx->usingClause(0), + "USING inside an DELETE or INSERT is"); + } + + parsedQuery_._rootGraphPattern = visit(ctx->groupGraphPattern()); + + parsedQuery_._clause = parsedQuery::UpdateClause(); + visitIf(&parsedQuery_.updateClause().toInsert_, ctx->insertClause()); + visitIf(&parsedQuery_.updateClause().toDelete_, ctx->deleteClause()); + + return parsedQuery_; +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::DeleteClauseContext* ctx) { + return visit(ctx->quadPattern()); +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::InsertClauseContext* ctx) { + return visit(ctx->quadPattern()); +} + +// ____________________________________________________________________________________ +GraphOrDefault Visitor::visit(Parser::GraphOrDefaultContext* ctx) { + if (ctx->iri()) { + return visit(ctx->iri()); + } else { + return DEFAULT{}; + } +} + +// ____________________________________________________________________________________ +GraphRef Visitor::visit(Parser::GraphRefContext* ctx) { + return visit(ctx->iri()); +} + +// ____________________________________________________________________________________ +GraphRefAll Visitor::visit(Parser::GraphRefAllContext* ctx) { + if (ctx->graphRef()) { + return visit(ctx->graphRef()); + } else if (ctx->DEFAULT()) { + return DEFAULT{}; + } else if (ctx->NAMED()) { + return NAMED{}; + } else if (ctx->ALL()) { + return ALL{}; + } else { + AD_FAIL(); + } +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::QuadPatternContext* ctx) { + return visit(ctx->quads()); +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::QuadDataContext* ctx) { + auto quads = visit(ctx->quads()); + auto checkAndReportVar = [&ctx](const TripleComponent& term) { + if (term.isVariable()) { + reportError(ctx->quads(), "Variables (" + term.getVariable().name() + + ") are not allowed here."); + } + }; + + for (const auto& quad : quads) { + checkAndReportVar(quad.s_); + checkAndReportVar(quad.p_); + checkAndReportVar(quad.o_); + } + + return quads; +} + +// ____________________________________________________________________________________ +vector Visitor::visit(Parser::QuadsContext* ctx) { + if (!ctx->quadsNotTriples().empty()) { + // Could also be default; disallow completely for now. + reportNotSupported(ctx->quadsNotTriples(0), "Named graphs are"); + } + + AD_CORRECTNESS_CHECK(ctx->triplesTemplate().size() == 1); + + auto convertTriple = + [](const std::array& triple) -> SparqlTripleSimple { + return {visitGraphTerm(triple[0]), visitGraphTerm(triple[1]), + visitGraphTerm(triple[2])}; + }; + + return ad_utility::transform(visit(ctx->triplesTemplate(0)), convertTriple); +} + // ____________________________________________________________________________________ GraphPattern Visitor::visit(Parser::GroupGraphPatternContext* ctx) { GraphPattern pattern; @@ -411,19 +635,6 @@ Visitor::OperationOrFilterAndMaybeTriples Visitor::visit( // ____________________________________________________________________________________ BasicGraphPattern Visitor::visit(Parser::TriplesBlockContext* ctx) { - auto visitGraphTerm = [](const GraphTerm& graphTerm) { - return graphTerm.visit([](const T& element) -> TripleComponent { - if constexpr (std::is_same_v) { - return element; - } else if constexpr (std::is_same_v || - std::is_same_v) { - return TurtleStringParser::parseTripleObject( - element.toSparql()); - } else { - return element.toSparql(); - } - }); - }; auto varToPropertyPath = [](const Variable& var) { return PropertyPath::fromVariable(var); }; @@ -436,15 +647,13 @@ BasicGraphPattern Visitor::visit(Parser::TriplesBlockContext* ctx) { propertyPathIdentity}, varOrPath); }; - auto registerIfVariable = [this](const auto& variant) { if (holds_alternative(variant)) { addVisibleVariable(std::get(variant)); } }; - auto convertAndRegisterTriple = - [&visitGraphTerm, &visitVarOrPath, ®isterIfVariable]( + [&visitVarOrPath, ®isterIfVariable]( const TripleWithPropertyPath& triple) -> SparqlTriple { registerIfVariable(triple.subject_); registerIfVariable(triple.predicate_); @@ -2170,3 +2379,18 @@ void Visitor::checkUnsupportedLangOperationAllowFilters( ad_utility::antlr_utility::generateAntlrExceptionMetadata(ctx)); } } + +// _____________________________________________________________________________ +TripleComponent SparqlQleverVisitor::visitGraphTerm( + const GraphTerm& graphTerm) { + return graphTerm.visit([](const T& element) -> TripleComponent { + if constexpr (std::is_same_v) { + return element; + } else if constexpr (std::is_same_v || std::is_same_v) { + return TurtleStringParser::parseTripleObject( + element.toSparql()); + } else { + return element.toSparql(); + } + }); +} diff --git a/src/parser/sparqlParser/SparqlQleverVisitor.h b/src/parser/sparqlParser/SparqlQleverVisitor.h index aa8a5d17c5..f54ebecd76 100644 --- a/src/parser/sparqlParser/SparqlQleverVisitor.h +++ b/src/parser/sparqlParser/SparqlQleverVisitor.h @@ -19,6 +19,7 @@ #include "parser/ParsedQuery.h" #include "parser/RdfEscaping.h" #include "parser/data/BlankNode.h" +#include "parser/data/GraphRef.h" #include "parser/data/Iri.h" #include "parser/data/SolutionModifiers.h" #include "parser/data/Types.h" @@ -127,7 +128,7 @@ class SparqlQleverVisitor { ParsedQuery visit(Parser::QueryOrUpdateContext* ctx); // ___________________________________________________________________________ - [[nodiscard]] ParsedQuery visit(Parser::QueryContext* ctx); + ParsedQuery visit(Parser::QueryContext* ctx); // ___________________________________________________________________________ void visit(Parser::PrologueContext* ctx); @@ -138,21 +139,19 @@ class SparqlQleverVisitor { // ___________________________________________________________________________ void visit(Parser::PrefixDeclContext* ctx); - [[nodiscard]] ParsedQuery visit(Parser::SelectQueryContext* ctx); + ParsedQuery visit(Parser::SelectQueryContext* ctx); - [[nodiscard]] SubQueryAndMaybeValues visit(Parser::SubSelectContext* ctx); + SubQueryAndMaybeValues visit(Parser::SubSelectContext* ctx); - [[nodiscard]] parsedQuery::SelectClause visit( - Parser::SelectClauseContext* ctx); + parsedQuery::SelectClause visit(Parser::SelectClauseContext* ctx); - [[nodiscard]] std::variant visit( - Parser::VarOrAliasContext* ctx); + std::variant visit(Parser::VarOrAliasContext* ctx); - [[nodiscard]] Alias visit(Parser::AliasContext* ctx); + Alias visit(Parser::AliasContext* ctx); - [[nodiscard]] Alias visit(Parser::AliasWithoutBracketsContext* ctx); + Alias visit(Parser::AliasWithoutBracketsContext* ctx); - [[nodiscard]] ParsedQuery visit(Parser::ConstructQueryContext* ctx); + ParsedQuery visit(Parser::ConstructQueryContext* ctx); // The parser rules for which the visit overload is annotated [[noreturn]] // will always throw an exception because the corresponding feature is not @@ -171,156 +170,180 @@ class SparqlQleverVisitor { [[noreturn]] static void visit(Parser::SourceSelectorContext* ctx); - [[nodiscard]] PatternAndVisibleVariables visit( - Parser::WhereClauseContext* ctx); + PatternAndVisibleVariables visit(Parser::WhereClauseContext* ctx); - [[nodiscard]] SolutionModifiers visit(Parser::SolutionModifierContext* ctx); + SolutionModifiers visit(Parser::SolutionModifierContext* ctx); - [[nodiscard]] vector visit(Parser::GroupClauseContext* ctx); + vector visit(Parser::GroupClauseContext* ctx); - [[nodiscard]] GroupKey visit(Parser::GroupConditionContext* ctx); + GroupKey visit(Parser::GroupConditionContext* ctx); - [[nodiscard]] vector visit(Parser::HavingClauseContext* ctx); + vector visit(Parser::HavingClauseContext* ctx); - [[nodiscard]] SparqlFilter visit(Parser::HavingConditionContext* ctx); + SparqlFilter visit(Parser::HavingConditionContext* ctx); - [[nodiscard]] OrderClause visit(Parser::OrderClauseContext* ctx); + OrderClause visit(Parser::OrderClauseContext* ctx); - [[nodiscard]] OrderKey visit(Parser::OrderConditionContext* ctx); + OrderKey visit(Parser::OrderConditionContext* ctx); - [[nodiscard]] LimitOffsetClause visit(Parser::LimitOffsetClausesContext* ctx); + LimitOffsetClause visit(Parser::LimitOffsetClausesContext* ctx); - [[nodiscard]] static uint64_t visit(Parser::LimitClauseContext* ctx); + static uint64_t visit(Parser::LimitClauseContext* ctx); - [[nodiscard]] static uint64_t visit(Parser::OffsetClauseContext* ctx); + static uint64_t visit(Parser::OffsetClauseContext* ctx); - [[nodiscard]] static uint64_t visit(Parser::TextLimitClauseContext* ctx); + static uint64_t visit(Parser::TextLimitClauseContext* ctx); - [[nodiscard]] std::optional visit( - Parser::ValuesClauseContext* ctx); + std::optional visit(Parser::ValuesClauseContext* ctx); - [[nodiscard]] Triples visit(Parser::TriplesTemplateContext* ctx); + ParsedQuery visit(Parser::UpdateContext* ctx); - [[nodiscard]] ParsedQuery::GraphPattern visit( - Parser::GroupGraphPatternContext* ctx); + ParsedQuery visit(Parser::Update1Context* ctx); - [[nodiscard]] OperationsAndFilters visit( - Parser::GroupGraphPatternSubContext* ctx); + [[noreturn]] void visit(const Parser::LoadContext* ctx) const; - [[nodiscard]] OperationOrFilterAndMaybeTriples visit( + ParsedQuery visit(Parser::ClearContext* ctx); + + [[noreturn]] void visit(const Parser::DropContext* ctx) const; + + [[noreturn]] void visit(const Parser::CreateContext* ctx) const; + + [[noreturn]] void visit(const Parser::AddContext* ctx) const; + + [[noreturn]] void visit(const Parser::MoveContext* ctx) const; + + [[noreturn]] void visit(const Parser::CopyContext* ctx) const; + + vector visit(Parser::InsertDataContext* ctx); + + vector visit(Parser::DeleteDataContext* ctx); + + std::pair, ParsedQuery::GraphPattern> visit( + Parser::DeleteWhereContext* ctx); + + ParsedQuery visit(Parser::ModifyContext* ctx); + + vector visit(Parser::DeleteClauseContext* ctx); + + vector visit(Parser::InsertClauseContext* ctx); + + GraphOrDefault visit(Parser::GraphOrDefaultContext* ctx); + + GraphRef visit(Parser::GraphRefContext* ctx); + + GraphRefAll visit(Parser::GraphRefAllContext* ctx); + + vector visit(Parser::QuadPatternContext* ctx); + + vector visit(Parser::QuadDataContext* ctx); + + vector visit(Parser::QuadsContext* ctx); + + Triples visit(Parser::TriplesTemplateContext* ctx); + + ParsedQuery::GraphPattern visit(Parser::GroupGraphPatternContext* ctx); + + OperationsAndFilters visit(Parser::GroupGraphPatternSubContext* ctx); + + OperationOrFilterAndMaybeTriples visit( Parser::GraphPatternNotTriplesAndMaybeTriplesContext* ctx); - [[nodiscard]] parsedQuery::BasicGraphPattern visit( - Parser::TriplesBlockContext* graphTerm); + parsedQuery::BasicGraphPattern visit(Parser::TriplesBlockContext* graphTerm); // Filter clauses are no independent graph patterns themselves, but their // scope is always the complete graph pattern enclosing them. - [[nodiscard]] OperationOrFilter visit( - Parser::GraphPatternNotTriplesContext* ctx); + OperationOrFilter visit(Parser::GraphPatternNotTriplesContext* ctx); - [[nodiscard]] parsedQuery::GraphPatternOperation visit( + parsedQuery::GraphPatternOperation visit( Parser::OptionalGraphPatternContext* ctx); [[noreturn]] static parsedQuery::GraphPatternOperation visit( const Parser::GraphGraphPatternContext* ctx); - [[nodiscard]] parsedQuery::Service visit( - Parser::ServiceGraphPatternContext* ctx); + parsedQuery::Service visit(Parser::ServiceGraphPatternContext* ctx); - [[nodiscard]] parsedQuery::GraphPatternOperation visit( - Parser::BindContext* ctx); + parsedQuery::GraphPatternOperation visit(Parser::BindContext* ctx); - [[nodiscard]] parsedQuery::GraphPatternOperation visit( - Parser::InlineDataContext* ctx); + parsedQuery::GraphPatternOperation visit(Parser::InlineDataContext* ctx); - [[nodiscard]] parsedQuery::Values visit(Parser::DataBlockContext* ctx); + parsedQuery::Values visit(Parser::DataBlockContext* ctx); - [[nodiscard]] parsedQuery::SparqlValues visit( - Parser::InlineDataOneVarContext* ctx); + parsedQuery::SparqlValues visit(Parser::InlineDataOneVarContext* ctx); - [[nodiscard]] parsedQuery::SparqlValues visit( - Parser::InlineDataFullContext* ctx); + parsedQuery::SparqlValues visit(Parser::InlineDataFullContext* ctx); - [[nodiscard]] vector visit( - Parser::DataBlockSingleContext* ctx); + vector visit(Parser::DataBlockSingleContext* ctx); - [[nodiscard]] TripleComponent visit(Parser::DataBlockValueContext* ctx); + TripleComponent visit(Parser::DataBlockValueContext* ctx); - [[nodiscard]] GraphPatternOperation visit( - Parser::MinusGraphPatternContext* ctx); + GraphPatternOperation visit(Parser::MinusGraphPatternContext* ctx); - [[nodiscard]] GraphPatternOperation visit( - Parser::GroupOrUnionGraphPatternContext* ctx); + GraphPatternOperation visit(Parser::GroupOrUnionGraphPatternContext* ctx); - [[nodiscard]] SparqlFilter visit(Parser::FilterRContext* ctx); + SparqlFilter visit(Parser::FilterRContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::ConstraintContext* ctx); + ExpressionPtr visit(Parser::ConstraintContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::FunctionCallContext* ctx); + ExpressionPtr visit(Parser::FunctionCallContext* ctx); - [[nodiscard]] vector visit(Parser::ArgListContext* ctx); + vector visit(Parser::ArgListContext* ctx); std::vector visit(Parser::ExpressionListContext* ctx); - [[nodiscard]] std::optional visit( + std::optional visit( Parser::ConstructTemplateContext* ctx); - [[nodiscard]] Triples visit(Parser::ConstructTriplesContext* ctx); + Triples visit(Parser::ConstructTriplesContext* ctx); - [[nodiscard]] Triples visit(Parser::TriplesSameSubjectContext* ctx); + Triples visit(Parser::TriplesSameSubjectContext* ctx); - [[nodiscard]] PredicateObjectPairsAndTriples visit( - Parser::PropertyListContext* ctx); + PredicateObjectPairsAndTriples visit(Parser::PropertyListContext* ctx); - [[nodiscard]] PredicateObjectPairsAndTriples visit( + PredicateObjectPairsAndTriples visit( Parser::PropertyListNotEmptyContext* ctx); - [[nodiscard]] GraphTerm visit(Parser::VerbContext* ctx); + GraphTerm visit(Parser::VerbContext* ctx); - [[nodiscard]] ObjectsAndTriples visit(Parser::ObjectListContext* ctx); + ObjectsAndTriples visit(Parser::ObjectListContext* ctx); - [[nodiscard]] SubjectOrObjectAndTriples visit(Parser::ObjectRContext* ctx); + SubjectOrObjectAndTriples visit(Parser::ObjectRContext* ctx); - [[nodiscard]] vector visit( + vector visit( Parser::TriplesSameSubjectPathContext* ctx); - [[nodiscard]] std::optional visit( + std::optional visit( Parser::PropertyListPathContext* ctx); - [[nodiscard]] PathObjectPairsAndTriples visit( - Parser::PropertyListPathNotEmptyContext* ctx); + PathObjectPairsAndTriples visit(Parser::PropertyListPathNotEmptyContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::VerbPathContext* ctx); + PropertyPath visit(Parser::VerbPathContext* ctx); - [[nodiscard]] static Variable visit(Parser::VerbSimpleContext* ctx); + static Variable visit(Parser::VerbSimpleContext* ctx); - [[nodiscard]] PathObjectPairsAndTriples visit( - Parser::TupleWithoutPathContext* term); + PathObjectPairsAndTriples visit(Parser::TupleWithoutPathContext* term); - [[nodiscard]] PathObjectPairsAndTriples visit( - Parser::TupleWithPathContext* ctx); + PathObjectPairsAndTriples visit(Parser::TupleWithPathContext* ctx); - [[nodiscard]] ad_utility::sparql_types::VarOrPath visit( + ad_utility::sparql_types::VarOrPath visit( Parser::VerbPathOrSimpleContext* ctx); - [[nodiscard]] ObjectsAndPathTriples visit(Parser::ObjectListPathContext* ctx); + ObjectsAndPathTriples visit(Parser::ObjectListPathContext* ctx); - [[nodiscard]] SubjectOrObjectAndPathTriples visit( - Parser::ObjectPathContext* ctx); + SubjectOrObjectAndPathTriples visit(Parser::ObjectPathContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::PathContext* ctx); + PropertyPath visit(Parser::PathContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::PathAlternativeContext* ctx); + PropertyPath visit(Parser::PathAlternativeContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::PathSequenceContext* ctx); + PropertyPath visit(Parser::PathSequenceContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::PathEltContext* ctx); + PropertyPath visit(Parser::PathEltContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::PathEltOrInverseContext* ctx); + PropertyPath visit(Parser::PathEltOrInverseContext* ctx); [[noreturn]] static void visit(Parser::PathModContext* ctx); - [[nodiscard]] PropertyPath visit(Parser::PathPrimaryContext* ctx); + PropertyPath visit(Parser::PathPrimaryContext* ctx); [[noreturn]] static PropertyPath visit( const Parser::PathNegatedPropertySetContext*); @@ -330,52 +353,47 @@ class SparqlQleverVisitor { /// Note that in the SPARQL grammar the INTEGER rule refers to positive /// integers without an explicit sign. - [[nodiscard]] static uint64_t visit(Parser::IntegerContext* ctx); + static uint64_t visit(Parser::IntegerContext* ctx); - [[nodiscard]] SubjectOrObjectAndTriples visit( - Parser::TriplesNodeContext* ctx); + SubjectOrObjectAndTriples visit(Parser::TriplesNodeContext* ctx); - [[nodiscard]] SubjectOrObjectAndTriples visit( - Parser::BlankNodePropertyListContext* ctx); + SubjectOrObjectAndTriples visit(Parser::BlankNodePropertyListContext* ctx); SubjectOrObjectAndPathTriples visit(Parser::TriplesNodePathContext* ctx); SubjectOrObjectAndPathTriples visit( Parser::BlankNodePropertyListPathContext* ctx); - [[nodiscard]] SubjectOrObjectAndTriples visit(Parser::CollectionContext* ctx); + SubjectOrObjectAndTriples visit(Parser::CollectionContext* ctx); [[noreturn]] SubjectOrObjectAndPathTriples visit( Parser::CollectionPathContext* ctx); - [[nodiscard]] SubjectOrObjectAndTriples visit(Parser::GraphNodeContext* ctx); + SubjectOrObjectAndTriples visit(Parser::GraphNodeContext* ctx); - [[nodiscard]] SubjectOrObjectAndPathTriples visit( - Parser::GraphNodePathContext* ctx); + SubjectOrObjectAndPathTriples visit(Parser::GraphNodePathContext* ctx); - [[nodiscard]] GraphTerm visit(Parser::VarOrTermContext* ctx); + GraphTerm visit(Parser::VarOrTermContext* ctx); - [[nodiscard]] GraphTerm visit(Parser::VarOrIriContext* ctx); + GraphTerm visit(Parser::VarOrIriContext* ctx); - [[nodiscard]] static Variable visit(Parser::VarContext* ctx); + static Variable visit(Parser::VarContext* ctx); - [[nodiscard]] GraphTerm visit(Parser::GraphTermContext* ctx); + GraphTerm visit(Parser::GraphTermContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::ExpressionContext* ctx); + ExpressionPtr visit(Parser::ExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit( - Parser::ConditionalOrExpressionContext* ctx); + ExpressionPtr visit(Parser::ConditionalOrExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit( - Parser::ConditionalAndExpressionContext* ctx); + ExpressionPtr visit(Parser::ConditionalAndExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::ValueLogicalContext* ctx); + ExpressionPtr visit(Parser::ValueLogicalContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::RelationalExpressionContext* ctx); + ExpressionPtr visit(Parser::RelationalExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::NumericExpressionContext* ctx); + ExpressionPtr visit(Parser::NumericExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::AdditiveExpressionContext* ctx); + ExpressionPtr visit(Parser::AdditiveExpressionContext* ctx); // Helper structs, needed in the following `visit` functions. Combine an // explicit operator (+ - * /) with an expression. @@ -385,41 +403,35 @@ class SparqlQleverVisitor { ExpressionPtr expression_; }; - [[nodiscard]] OperatorAndExpression visit( + OperatorAndExpression visit( Parser::MultiplicativeExpressionWithSignContext* ctx); - [[nodiscard]] OperatorAndExpression visit( - Parser::PlusSubexpressionContext* ctx); + OperatorAndExpression visit(Parser::PlusSubexpressionContext* ctx); - [[nodiscard]] OperatorAndExpression visit( - Parser::MinusSubexpressionContext* ctx); + OperatorAndExpression visit(Parser::MinusSubexpressionContext* ctx); - [[nodiscard]] OperatorAndExpression visit( + OperatorAndExpression visit( Parser::MultiplicativeExpressionWithLeadingSignButNoSpaceContext* ctx); - [[nodiscard]] ExpressionPtr visit( - Parser::MultiplicativeExpressionContext* ctx); + ExpressionPtr visit(Parser::MultiplicativeExpressionContext* ctx); - [[nodiscard]] OperatorAndExpression visit( - Parser::MultiplyOrDivideExpressionContext* ctx); + OperatorAndExpression visit(Parser::MultiplyOrDivideExpressionContext* ctx); - [[nodiscard]] OperatorAndExpression visit( - Parser::MultiplyExpressionContext* ctx); + OperatorAndExpression visit(Parser::MultiplyExpressionContext* ctx); - [[nodiscard]] OperatorAndExpression visit( - Parser::DivideExpressionContext* ctx); + OperatorAndExpression visit(Parser::DivideExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::UnaryExpressionContext* ctx); + ExpressionPtr visit(Parser::UnaryExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::PrimaryExpressionContext* ctx); + ExpressionPtr visit(Parser::PrimaryExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::BrackettedExpressionContext* ctx); + ExpressionPtr visit(Parser::BrackettedExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::BuiltInCallContext* ctx); + ExpressionPtr visit(Parser::BuiltInCallContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::RegexExpressionContext* ctx); + ExpressionPtr visit(Parser::RegexExpressionContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::LangExpressionContext* ctx); + ExpressionPtr visit(Parser::LangExpressionContext* ctx); ExpressionPtr visit(Parser::SubstringExpressionContext* ctx); @@ -429,39 +441,35 @@ class SparqlQleverVisitor { [[noreturn]] static void visit(const Parser::NotExistsFuncContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::AggregateContext* ctx); + ExpressionPtr visit(Parser::AggregateContext* ctx); - [[nodiscard]] ExpressionPtr visit(Parser::IriOrFunctionContext* ctx); + ExpressionPtr visit(Parser::IriOrFunctionContext* ctx); - [[nodiscard]] std::string visit(Parser::RdfLiteralContext* ctx); + std::string visit(Parser::RdfLiteralContext* ctx); - [[nodiscard]] IntOrDouble visit(Parser::NumericLiteralContext* ctx); + IntOrDouble visit(Parser::NumericLiteralContext* ctx); - [[nodiscard]] static IntOrDouble visit( - Parser::NumericLiteralUnsignedContext* ctx); + static IntOrDouble visit(Parser::NumericLiteralUnsignedContext* ctx); - [[nodiscard]] static IntOrDouble visit( - Parser::NumericLiteralPositiveContext* ctx); + static IntOrDouble visit(Parser::NumericLiteralPositiveContext* ctx); - [[nodiscard]] static IntOrDouble visit( - Parser::NumericLiteralNegativeContext* ctx); + static IntOrDouble visit(Parser::NumericLiteralNegativeContext* ctx); - [[nodiscard]] static bool visit(Parser::BooleanLiteralContext* ctx); + static bool visit(Parser::BooleanLiteralContext* ctx); - [[nodiscard]] static RdfEscaping::NormalizedRDFString visit( - Parser::StringContext* ctx); + static RdfEscaping::NormalizedRDFString visit(Parser::StringContext* ctx); - [[nodiscard]] TripleComponent::Iri visit(Parser::IriContext* ctx); + TripleComponent::Iri visit(Parser::IriContext* ctx); - [[nodiscard]] static string visit(Parser::IrirefContext* ctx); + static string visit(Parser::IrirefContext* ctx); - [[nodiscard]] string visit(Parser::PrefixedNameContext* ctx); + string visit(Parser::PrefixedNameContext* ctx); - [[nodiscard]] GraphTerm visit(Parser::BlankNodeContext* ctx); + GraphTerm visit(Parser::BlankNodeContext* ctx); - [[nodiscard]] string visit(Parser::PnameLnContext* ctx); + string visit(Parser::PnameLnContext* ctx); - [[nodiscard]] string visit(Parser::PnameNsContext* ctx); + string visit(Parser::PnameNsContext* ctx); private: template @@ -469,7 +477,7 @@ class SparqlQleverVisitor { std::is_void_v().visit( std::declval()))>; - [[nodiscard]] BlankNode newBlankNode() { + BlankNode newBlankNode() { std::string label = std::to_string(_blankNodeCounter); _blankNodeCounter++; // true means automatically generated @@ -487,7 +495,7 @@ class SparqlQleverVisitor { // Process an IRI function call. This is used in both `visitFunctionCall` and // `visitIriOrFunction`. - [[nodiscard]] static ExpressionPtr processIriFunctionCall( + static ExpressionPtr processIriFunctionCall( const TripleComponent::Iri& iri, std::vector argList, const antlr4::ParserRuleContext*); @@ -500,11 +508,11 @@ class SparqlQleverVisitor { // Return the `SparqlExpressionPimpl` for a context that returns a // `ExpressionPtr` when visited. The descriptor is set automatically on the // `SparqlExpressionPimpl`. - [[nodiscard]] SparqlExpressionPimpl visitExpressionPimpl( - auto* ctx, bool allowLanguageFilters = false); + SparqlExpressionPimpl visitExpressionPimpl(auto* ctx, + bool allowLanguageFilters = false); template - [[nodiscard]] ExpressionPtr createExpression(auto... children) { + ExpressionPtr createExpression(auto... children) { return std::make_unique( std::array{std::move(children)...}); } @@ -516,7 +524,7 @@ class SparqlQleverVisitor { // Call `visit` for each of the `childContexts` and return the results of // those calls as a `vector`. template - [[nodiscard]] auto visitVector(const std::vector& childContexts) + auto visitVector(const std::vector& childContexts) -> std::vector requires(!voidWhenVisited); @@ -524,13 +532,12 @@ class SparqlQleverVisitor { // cast the result to `Out` and return it. Requires that for all of the // `ctxs`, `visit(ctxs)` is convertible to `Out`. template - [[nodiscard]] Out visitAlternative(Contexts*... ctxs); + Out visitAlternative(Contexts*... ctxs); // Returns `std::nullopt` if the pointer is the `nullptr`. Otherwise return // `visit(ctx)`. template - [[nodiscard]] auto visitOptional(Ctx* ctx) - -> std::optional; + auto visitOptional(Ctx* ctx) -> std::optional; /// If `ctx` is not `nullptr`, visit it, convert the result to `Intermediate` /// and assign it to `*target`. The case where `Intermediate!=Target` is @@ -569,7 +576,7 @@ class SparqlQleverVisitor { // Parse both `ConstructTriplesContext` and `TriplesTemplateContext` because // they have the same structure. template - [[nodiscard]] Triples parseTriplesConstruction(Context* ctx); + Triples parseTriplesConstruction(Context* ctx); // If the triple is a special triple for the text index (i.e. its predicate is // either `ql:contains-word` or `ql:contains-entity`, register the magic @@ -578,4 +585,7 @@ class SparqlQleverVisitor { // part of the query result. void setMatchingWordAndScoreVisibleIfPresent( auto* ctx, const TripleWithPropertyPath& triple); + + // Constructs a TripleComponent from a GraphTerm. + static TripleComponent visitGraphTerm(const GraphTerm& graphTerm); }; diff --git a/test/SparqlAntlrParserTest.cpp b/test/SparqlAntlrParserTest.cpp index 7267e9edd9..73afdc996d 100644 --- a/test/SparqlAntlrParserTest.cpp +++ b/test/SparqlAntlrParserTest.cpp @@ -1625,7 +1625,10 @@ TEST(SparqlParser, binaryStringExpressions) { expectBuiltInCall("STRBEFORE(?x, ?y)", makeMatcher(&makeStrBeforeExpression)); } -TEST(SparqlParser, updateUnsupported) { +// Update queries are WIP. The individual parts to parse some update queries +// are in place the code to process them is still unfinished. Therefore we +// don't accept update queries. +TEST(SparqlParser, updateQueryUnsupported) { auto expectUpdateFails = ExpectParseFails<&Parser::queryOrUpdate>{}; auto contains = [](const std::string& s) { return ::testing::HasSubstr(s); }; auto updateUnsupported = @@ -1647,3 +1650,86 @@ TEST(SparqlParser, updateUnsupported) { expectUpdateFails("MOVE DEFAULT TO GRAPH ", updateUnsupported); expectUpdateFails("COPY GRAPH TO GRAPH ", updateUnsupported); } + +TEST(SparqlParser, UpdateQuery) { + auto expectUpdate = ExpectCompleteParse<&Parser::update>{ + {{INTERNAL_PREDICATE_PREFIX_NAME, INTERNAL_PREDICATE_PREFIX_IRI}}}; + auto expectUpdateFails = ExpectParseFails<&Parser::update>{}; + auto Iri = [](std::string_view stringWithBrackets) { + return TripleComponent::Iri::fromIriref(stringWithBrackets); + }; + auto Literal = [](std::string s) { + return TripleComponent::Literal::fromStringRepresentation(s); + }; + + expectUpdate("INSERT DATA { }", + m::UpdateQuery({}, {{Iri(""), Iri(""), Iri("")}}, + m::GraphPattern())); + expectUpdate( + "INSERT DATA { \"foo:bar\" }", + m::UpdateQuery({}, {{Iri(""), Iri(""), Literal("\"foo:bar\"")}}, + m::GraphPattern())); + expectUpdate("DELETE DATA { }", + m::UpdateQuery({{Iri(""), Iri(""), Iri("")}}, {}, + m::GraphPattern())); + expectUpdate( + "DELETE { ?a } WHERE { ?a }", + m::UpdateQuery( + {{Var("?a"), Iri(""), Iri("")}}, {}, + m::GraphPattern(m::Triples({{Iri(""), "", Var{"?a"}}})))); + expectUpdate( + "DELETE { ?a } INSERT { ?a } WHERE { ?a }", + m::UpdateQuery( + {{Var("?a"), Iri(""), Iri("")}}, + {{Iri(""), Var("?a"), Iri("")}}, + m::GraphPattern(m::Triples({{Iri(""), "", Var{"?a"}}})))); + expectUpdate( + "DELETE WHERE { ?a ?c }", + m::UpdateQuery( + {{Var("?a"), Iri(""), Var("?c")}}, {}, + m::GraphPattern(m::Triples({{Var{"?a"}, "", Var{"?c"}}})))); + expectUpdate("CLEAR DEFAULT", + m::UpdateQuery({{Var("?s"), Var("?p"), Var("?o")}}, {}, + m::GraphPattern( + m::Triples({{Var("?s"), "?p", Var("?o")}})))); + expectUpdateFails("INSERT DATA { ?a ?b ?c }"); + expectUpdateFails("WITH DELETE { ?a ?b ?c } WHERE { ?a ?b ?c }"); + expectUpdateFails("DELETE { ?a ?b ?c } USING WHERE { ?a ?b ?c }"); + expectUpdateFails("INSERT DATA { GRAPH { } }"); + // Unsupported features. + expectUpdateFails( + "INSERT DATA { } ; INSERT { ?a } WHERE { ?a " + "}"); + expectUpdateFails("LOAD "); + expectUpdateFails("CLEAR NAMED"); + expectUpdateFails("CLEAR GRAPH "); + expectUpdateFails("CREATE GRAPH "); + expectUpdateFails("DROP GRAPH "); + expectUpdateFails("MOVE GRAPH TO DEFAULT"); + expectUpdateFails("ADD DEFAULT TO GRAPH "); + expectUpdateFails("COPY DEFAULT TO GRAPH "); + expectUpdateFails( + "DELETE { ?a } USING NAMED WHERE { ?a }"); + expectUpdateFails("WITH DELETE { ?a } WHERE { ?a }"); +} + +TEST(SparqlParser, GraphOrDefault) { + // Explicitly test this part, because all features that use it are not yet + // supported. + auto expectGraphOrDefault = ExpectCompleteParse<&Parser::graphOrDefault>{ + {{INTERNAL_PREDICATE_PREFIX_NAME, INTERNAL_PREDICATE_PREFIX_IRI}}}; + expectGraphOrDefault("DEFAULT", testing::VariantWith(testing::_)); + expectGraphOrDefault( + "GRAPH ", + testing::VariantWith(AD_PROPERTY( + TripleComponent::Iri, toStringRepresentation, testing::Eq("")))); +} + +TEST(SparqlParser, GraphRef) { + auto expectGraphRefAll = ExpectCompleteParse<&Parser::graphRefAll>{ + {{INTERNAL_PREDICATE_PREFIX_NAME, INTERNAL_PREDICATE_PREFIX_IRI}}}; + expectGraphRefAll("DEFAULT", m::Variant()); + expectGraphRefAll("NAMED", m::Variant()); + expectGraphRefAll("ALL", m::Variant()); + expectGraphRefAll("GRAPH ", m::GraphRefIri("")); +} diff --git a/test/SparqlAntlrParserTestHelpers.h b/test/SparqlAntlrParserTestHelpers.h index 9972deca8c..af89918a88 100644 --- a/test/SparqlAntlrParserTestHelpers.h +++ b/test/SparqlAntlrParserTestHelpers.h @@ -824,9 +824,9 @@ inline auto ConstructQuery(const std::vector>& elems, -> Matcher { return testing::AllOf( AD_PROPERTY(ParsedQuery, hasConstructClause, testing::IsTrue()), - AD_PROPERTY( - ParsedQuery, constructClause, - AD_FIELD(parsedQuery::ConstructClause, triples_, testing::Eq(elems))), + AD_PROPERTY(ParsedQuery, constructClause, + AD_FIELD(parsedQuery::ConstructClause, triples_, + testing::ElementsAreArray(elems))), RootGraphPattern(m)); } @@ -836,4 +836,28 @@ inline auto VisibleVariables = return AD_PROPERTY(ParsedQuery, getVisibleVariables, testing::Eq(elems)); }; +inline auto UpdateQuery = + [](const std::vector& toDelete, + const std::vector& toInsert, + const Matcher& graphPatternMatcher) + -> Matcher { + return testing::AllOf( + AD_PROPERTY(ParsedQuery, hasUpdateClause, testing::IsTrue()), + AD_PROPERTY(ParsedQuery, updateClause, + AD_FIELD(parsedQuery::UpdateClause, toDelete_, + testing::ElementsAreArray(toDelete))), + AD_PROPERTY(ParsedQuery, updateClause, + AD_FIELD(parsedQuery::UpdateClause, toInsert_, + testing::ElementsAreArray(toInsert))), + RootGraphPattern(graphPatternMatcher)); +}; + +template +auto inline Variant = []() { return testing::VariantWith(testing::_); }; + +auto inline GraphRefIri = [](const string& iri) { + return testing::VariantWith(AD_PROPERTY( + TripleComponent::Iri, toStringRepresentation, testing::Eq(iri))); +}; + } // namespace matchers