Skip to content

Commit

Permalink
IsSomethingExpression now returns respective IsDatatypeExpression pre…
Browse files Browse the repository at this point in the history
…filter
  • Loading branch information
realHannes committed Feb 6, 2025
1 parent 1b97db3 commit a408822
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 4 deletions.
50 changes: 46 additions & 4 deletions src/engine/sparqlExpressions/IsSomethingExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Chair of Algorithms and Data Structures.
// Author: Hannah Bast <[email protected]>

#include "engine/sparqlExpressions/LiteralExpression.h"
#include "engine/sparqlExpressions/NaryExpressionImpl.h"
#include "engine/sparqlExpressions/SparqlExpressionValueGetters.h"

Expand All @@ -23,18 +24,59 @@ namespace detail {
// `SparqlExpression::Ptr` and returns a `unique_ptr` to a new instance of
// `...Expression` (`std::move` the arguments into the constructor). The
// function should be declared in `NaryExpression.h`.
template <typename NaryOperation, prefilterExpressions::IsDatatype Datatype>
requires(isOperation<NaryOperation>)
class IsDatatypeExpressionImpl : public NaryExpression<NaryOperation> {
public:
using NaryExpression<NaryOperation>::NaryExpression;
std::vector<PrefilterExprVariablePair> getPrefilterExpressionForMetadata(
[[maybe_unused]] bool isNegated) const override {
using namespace prefilterExpressions;
std::vector<PrefilterExprVariablePair> prefilterVec;
const SparqlExpression* childExpr = this->getNthChild(0).value_or(nullptr);
if (!childExpr) {
return prefilterVec;
}

Check warning on line 39 in src/engine/sparqlExpressions/IsSomethingExpressions.cpp

View check run for this annotation

Codecov / codecov/patch

src/engine/sparqlExpressions/IsSomethingExpressions.cpp#L38-L39

Added lines #L38 - L39 were not covered by tests
// Pre-filtering is only applicable if `isDatatype()` references a
// `VariableExpression` (e.g. `isLiteral(?x)`).
const auto* variableExpr =
dynamic_cast<const VariableExpression*>(childExpr);
if (!variableExpr) {
return prefilterVec;
}

prefilterVec.emplace_back(
std::make_unique<IsDatatypeExpression<Datatype>>(),
variableExpr->value());
return prefilterVec;
}
};

//______________________________________________________________________________
// 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<std::identity, IsIriValueGetter>>;
using isLiteralExpression = NARY<1, FV<std::identity, IsLiteralValueGetter>>;
using isNumericExpression = NARY<1, FV<std::identity, IsNumericValueGetter>>;
template <typename Getter, prefilterExpressions::IsDatatype Datatype>
using IsDtypeExpression =
IsDatatypeExpressionImpl<Operation<1, FV<std::identity, Getter>>, Datatype>;

using isLiteralExpression =
IsDtypeExpression<IsLiteralValueGetter,
prefilterExpressions::IsDatatype::LITERAL>;
using isNumericExpression =
IsDtypeExpression<IsNumericValueGetter,
prefilterExpressions::IsDatatype::NUMERIC>;
using isBlankExpression =
NARY<1, FV<std::identity, IsValueIdValueGetter<Datatype::BlankNodeIndex>>>;
IsDtypeExpression<IsValueIdValueGetter<Datatype::BlankNodeIndex>,
prefilterExpressions::IsDatatype::BLANK>;
using isIriExpression =
IsDtypeExpression<IsIriValueGetter, prefilterExpressions::IsDatatype::IRI>;

// We currently don't support pre-filtering for `isGeoPointExpression`.
using isGeoPointExpression =
NARY<1, FV<std::identity, IsValueIdValueGetter<Datatype::GeoPoint>>>;

//______________________________________________________________________________
// 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); };
Expand Down
20 changes: 20 additions & 0 deletions test/GetPrefilterExpressionFromSparqlExpressionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,26 @@ TEST(GetPrefilterExpressionFromSparqlExpression,
evalAndEqualityCheck(strStartsSprql(VocabId(0), VocabId(10)));
}

// Test PrefilterExpression creation for SparqlExpression isDatatype, where
// Datatype is Literal, Iri, Numeric or Blank.
//______________________________________________________________________________
TEST(GetPrefilterExpressionFromSparqlExpression,
getPrefilterExprForIsDatatypeExpr) {
const auto varX = Variable{"?x"};
// The following cases should return a <Prefilter, Variable> pair.
evalAndEqualityCheck(isIriSprql(varX), pr(isIri(), varX));
evalAndEqualityCheck(isLiteralSprql(varX), pr(isLit(), varX));
evalAndEqualityCheck(isNumericSprql(varX), pr(isNum(), varX));
evalAndEqualityCheck(isBlankSprql(varX), pr(isBlank(), varX));

// For the cases below, no prefilter procedure should be available given that
// the filter reference isn't a Variable.
evalAndEqualityCheck(isLiteralSprql(VocabId(0)));
evalAndEqualityCheck(isIriSprql(BlankNodeId(10)));
evalAndEqualityCheck(isBlankSprql(DoubleId(33.1)));
evalAndEqualityCheck(isNumericSprql((IntId(-0.01))));
}

// Test that the conditions required for a correct merge of child
// PrefilterExpressions are properly checked during the PrefilterExpression
// construction procedure. This check is applied in the SparqlExpression (for
Expand Down
33 changes: 33 additions & 0 deletions test/PrefilterExpressionTestHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,25 @@ std::unique_ptr<SparqlExpression> makeStringStartsWithSparqlExpression(
return makeStrStartsExpression(std::visit(getExpr, child0),
std::visit(getExpr, child1));
};

//______________________________________________________________________________
template <prefilterExpressions::IsDatatype Datatype>
std::unique_ptr<SparqlExpression> makeIsDatatypeStartsWithExpression(
const RelValues& child) {
using enum prefilterExpressions::IsDatatype;
auto childExpr = std::visit(getExpr, child);
if constexpr (Datatype == IRI) {
return makeIsIriExpression(std::move(childExpr));
} else if constexpr (Datatype == LITERAL) {
return makeIsLiteralExpression(std::move(childExpr));
} else if constexpr (Datatype == NUMERIC) {
return makeIsNumericExpression(std::move(childExpr));
} else {
static_assert(Datatype == BLANK);
return makeIsBlankExpression(std::move(childExpr));
}
}

} // namespace

//______________________________________________________________________________
Expand Down Expand Up @@ -197,4 +216,18 @@ constexpr auto notSprqlExpr = &makeUnaryNegateExpression;
// Create SparqlExpression `STRSTARTS`.
constexpr auto strStartsSprql = &makeStringStartsWithSparqlExpression;

//______________________________________________________________________________
// Create SparqlExpression `isIri`
constexpr auto isIriSprql =
&makeIsDatatypeStartsWithExpression<prefilterExpressions::IsDatatype::IRI>;
// Create SparqlExpression `isLiteral`
constexpr auto isLiteralSprql = &makeIsDatatypeStartsWithExpression<
prefilterExpressions::IsDatatype::LITERAL>;
// Create SparqlExpression `isNumeric`
constexpr auto isNumericSprql = &makeIsDatatypeStartsWithExpression<
prefilterExpressions::IsDatatype::NUMERIC>;
// Create SparqlExpression `isBlank`
constexpr auto isBlankSprql = &makeIsDatatypeStartsWithExpression<
prefilterExpressions::IsDatatype::BLANK>;

} // namespace makeSparqlExpression

0 comments on commit a408822

Please sign in to comment.