diff --git a/src/engine/sparqlExpressions/IsSomethingExpressions.cpp b/src/engine/sparqlExpressions/IsSomethingExpressions.cpp index 0d1780b756..cdfa18364d 100644 --- a/src/engine/sparqlExpressions/IsSomethingExpressions.cpp +++ b/src/engine/sparqlExpressions/IsSomethingExpressions.cpp @@ -24,14 +24,17 @@ namespace detail { // `...Expression` (`std::move` the arguments into the constructor). The // function should be declared in `NaryExpression.h`. -// Expressions for `isIRI`, `isBlank`, `isLiteral`, and `isNumeric`. Note that -// the value getters already return the correct `Id`, hence `std::identity`. +// Expressions for the builtin functions `isIRI`, `isBlank`, `isLiteral`, +// `isNumeric`, and the custom function `isWktPoint`. Note that the value +// getters already return the correct `Id`, hence `std::identity`. using isIriExpression = NARY<1, FV>; using isBlankExpression = NARY<1, FV>; using isLiteralExpression = NARY<1, FV>; using isNumericExpression = NARY<1, FV>; -// The expression for `bound` is slightly different because -// `IsValidValueGetter` returns a `bool` and not an `Id`. +using isWktPointExpression = NARY<1, FV>; + +// The expression for `bound` is slightly different as `IsValidValueGetter` +// returns a `bool` and not an `Id`. inline auto boolToId = [](bool b) { return Id::makeFromBool(b); }; using boundExpression = NARY<1, FV>; @@ -49,6 +52,9 @@ SparqlExpression::Ptr makeIsLiteralExpression(SparqlExpression::Ptr arg) { SparqlExpression::Ptr makeIsNumericExpression(SparqlExpression::Ptr arg) { return std::make_unique(std::move(arg)); } +SparqlExpression::Ptr makeIsWktPointExpression(SparqlExpression::Ptr arg) { + return std::make_unique(std::move(arg)); +} SparqlExpression::Ptr makeBoundExpression(SparqlExpression::Ptr arg) { return std::make_unique(std::move(arg)); } diff --git a/src/engine/sparqlExpressions/NaryExpression.h b/src/engine/sparqlExpressions/NaryExpression.h index 5237a2283a..c82e1b22ff 100644 --- a/src/engine/sparqlExpressions/NaryExpression.h +++ b/src/engine/sparqlExpressions/NaryExpression.h @@ -119,6 +119,7 @@ SparqlExpression::Ptr makeIsIriExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeIsBlankExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeIsLiteralExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeIsNumericExpression(SparqlExpression::Ptr child); +SparqlExpression::Ptr makeIsWktPointExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeBoundExpression(SparqlExpression::Ptr child); // For a `function` that takes `std::vector` (size only diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h index 6e7cd310ec..194c6c4b43 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h @@ -190,6 +190,18 @@ struct IsNumericValueGetter : Mixin { } }; +// Value getter for `isWktPoint`. +struct IsWktPointValueGetter : Mixin { + using Mixin::operator(); + Id operator()(ValueId id, const EvaluationContext*) const { + return Id::makeFromBool(id.getDatatype() == Datatype::GeoPoint); + } + + Id operator()(const LiteralOrIri&, const EvaluationContext*) const { + return Id::makeFromBool(false); + } +}; + /// This class can be used as the `ValueGetter` argument of Expression /// templates. It produces a `std::optional`. struct DateValueGetter : Mixin { diff --git a/src/parser/sparqlParser/SparqlQleverVisitor.cpp b/src/parser/sparqlParser/SparqlQleverVisitor.cpp index 777f29714d..6cfb5831de 100644 --- a/src/parser/sparqlParser/SparqlQleverVisitor.cpp +++ b/src/parser/sparqlParser/SparqlQleverVisitor.cpp @@ -112,6 +112,9 @@ ExpressionPtr Visitor::processIriFunctionCall( } else if (functionName == "latitude") { checkNumArgs(1); return sparqlExpression::makeLatitudeExpression(std::move(argList[0])); + } else if (functionName == "iswktpoint") { + checkNumArgs(1); + return sparqlExpression::makeIsWktPointExpression(std::move(argList[0])); } } else if (checkPrefix(MATH_PREFIX)) { if (functionName == "log") { diff --git a/test/SparqlAntlrParserTest.cpp b/test/SparqlAntlrParserTest.cpp index 0ee1705f46..598809e1ba 100644 --- a/test/SparqlAntlrParserTest.cpp +++ b/test/SparqlAntlrParserTest.cpp @@ -1655,6 +1655,8 @@ TEST(SparqlParser, FunctionCall) { matchUnary(&makeLatitudeExpression)); expectFunctionCall(absl::StrCat(geof, "longitude>(?x)"), matchUnary(&makeLongitudeExpression)); + expectFunctionCall(absl::StrCat(geof, "iswktpoint>(?x)"), + matchUnary(&makeIsWktPointExpression)); expectFunctionCall( absl::StrCat(geof, "distance>(?a, ?b)"), matchNary(&makeDistExpression, Variable{"?a"}, Variable{"?b"})); diff --git a/test/SparqlExpressionTest.cpp b/test/SparqlExpressionTest.cpp index ab5b3add68..da9083e23b 100644 --- a/test/SparqlExpressionTest.cpp +++ b/test/SparqlExpressionTest.cpp @@ -1117,6 +1117,7 @@ TEST(SparqlExpression, testToNumericExpression) { TEST(SparqlExpression, geoSparqlExpressions) { auto checkLat = testUnaryExpression<&makeLatitudeExpression>; auto checkLong = testUnaryExpression<&makeLongitudeExpression>; + auto checkIsWktPoint = testUnaryExpression<&makeIsWktPointExpression>; auto checkDist = std::bind_front(testNaryExpression, &makeDistExpression); auto p = GeoPoint(26.8, 24.3); @@ -1136,9 +1137,11 @@ TEST(SparqlExpression, geoSparqlExpressions) { checkLat(v, vLat); checkLong(v, vLng); + checkIsWktPoint(v, B(true)); checkDist(D(0.0), v, v); checkLat(idOrLitOrStringVec({"NotAPoint", I(12)}), Ids{U, U}); checkLong(idOrLitOrStringVec({D(4.2), "NotAPoint"}), Ids{U, U}); + checkIsWktPoint(IdOrLiteralOrIri{lit("NotAPoint")}, B(false)); checkDist(U, v, IdOrLiteralOrIri{I(12)}); checkDist(U, IdOrLiteralOrIri{I(12)}, v); checkDist(U, v, IdOrLiteralOrIri{lit("NotAPoint")});