diff --git a/src/engine/sparqlExpressions/LiteralExpression.h b/src/engine/sparqlExpressions/LiteralExpression.h index c67bfb1bb9..50e0de5fd3 100644 --- a/src/engine/sparqlExpressions/LiteralExpression.h +++ b/src/engine/sparqlExpressions/LiteralExpression.h @@ -213,6 +213,7 @@ struct SingleUseExpression : public SparqlExpression { std::span childrenImpl() override { return {}; } }; + } // namespace detail /// The actual instantiations and aliases of LiteralExpressions. @@ -224,4 +225,38 @@ using IdExpression = detail::LiteralExpression; using VectorIdExpression = detail::LiteralExpression>; using SingleUseExpression = detail::SingleUseExpression; + +namespace detail { + +//______________________________________________________________________________ +using IdOrLocalVocabEntry = prefilterExpressions::IdOrLocalVocabEntry; +// Given a `SparqlExpression*` pointing to a `LiteralExpression`, this helper +// function retrieves a corresponding `IdOrLocalVocabEntry` variant +// (`std::variant`) for `LiteralExpression`s that +// contain a suitable type. +// Given the boolean flag `stringAndIriOnly` is set to `true`, only `Literal`s, +// `Iri`s and `ValueId`s of type `VocabIndex`/`LocalVocabIndex` are returned. If +// `stringAndIriOnly` is set to `false` (default), all `ValueId` types retrieved +// from `LiteralExpression` will be returned. +inline std::optional +getIdOrLocalVocabEntryFromLiteralExpression(const SparqlExpression* child, + bool stringAndIriOnly = false) { + using enum Datatype; + if (const auto* idExpr = dynamic_cast(child)) { + auto idType = idExpr->value().getDatatype(); + if (stringAndIriOnly && idType != VocabIndex && idType != LocalVocabIndex) { + return std::nullopt; + } + return idExpr->value(); + } else if (const auto* literalExpr = + dynamic_cast(child)) { + return LocalVocabEntry{literalExpr->value()}; + } else if (const auto* iriExpr = dynamic_cast(child)) { + return LocalVocabEntry{iriExpr->value()}; + } else { + return std::nullopt; + } +} +} // namespace detail + } // namespace sparqlExpression diff --git a/src/engine/sparqlExpressions/PrefilterExpressionIndex.cpp b/src/engine/sparqlExpressions/PrefilterExpressionIndex.cpp index eb00fd466f..93af26df7e 100644 --- a/src/engine/sparqlExpressions/PrefilterExpressionIndex.cpp +++ b/src/engine/sparqlExpressions/PrefilterExpressionIndex.cpp @@ -7,6 +7,8 @@ #include #include "global/ValueIdComparators.h" +#include "util/ConstexprMap.h" +#include "util/OverloadCallOperator.h" namespace prefilterExpressions { @@ -207,34 +209,37 @@ std::vector PrefilterExpression::evaluateAndCheckImpl( return relevantBlocks; } +//______________________________________________________________________________ +ValueId PrefilterExpression::getValueIdFromIdOrLocalVocabEntry( + const IdOrLocalVocabEntry& referenceValue, LocalVocab& vocab) { + return std::visit(ad_utility::OverloadCallOperator{ + [](const ValueId& referenceId) { return referenceId; }, + [&vocab](const LocalVocabEntry& referenceLVE) { + return Id::makeFromLocalVocabIndex( + vocab.getIndexAndAddIfNotContained(referenceLVE)); + }}, + referenceValue); +} + // SECTION RELATIONAL OPERATIONS //______________________________________________________________________________ template std::unique_ptr RelationalExpression::logicalComplement() const { using enum CompOp; - switch (Comparison) { - case LT: - // Complement X < Y: X >= Y - return std::make_unique(referenceId_); - case LE: - // Complement X <= Y: X > Y - return std::make_unique(referenceId_); - case EQ: - // Complement X == Y: X != Y - return std::make_unique(referenceId_); - case NE: - // Complement X != Y: X == Y - return std::make_unique(referenceId_); - case GE: - // Complement X >= Y: X < Y - return std::make_unique(referenceId_); - case GT: - // Complement X > Y: X <= Y - return std::make_unique(referenceId_); - default: - AD_FAIL(); - } + using namespace ad_utility; + using P = std::pair; + // The complementation logic implemented with the following mapping procedure: + // (1) ?var < referenceValue -> ?var >= referenceValue + // (2) ?var <= referenceValue -> ?var > referenceValue + // (3) ?var >= referenceValue -> ?var < referenceValue + // (4) ?var > referenceValue -> ?var <= referenceValue + // (5) ?var = referenceValue -> ?var != referenceValue + // (6) ?var != referenceValue -> ?var = referenceValue + constexpr ConstexprMap complementMap( + {P{LT, GE}, P{LE, GT}, P{GE, LT}, P{GT, LE}, P{EQ, NE}, P{NE, EQ}}); + return std::make_unique>( + rightSideReferenceValue_); }; //______________________________________________________________________________ @@ -261,18 +266,21 @@ std::vector RelationalExpression::evaluateImpl( } } + LocalVocab vocab{}; + auto referenceId = + getValueIdFromIdOrLocalVocabEntry(rightSideReferenceValue_, vocab); // Use getRangesForId (from valueIdComparators) to extract the ranges // containing the relevant ValueIds. // For pre-filtering with CompOp::EQ, we have to consider empty ranges. - // Reason: The referenceId_ could be contained within the bounds formed by + // Reason: The referenceId could be contained within the bounds formed by // the IDs of firstTriple_ and lastTriple_ (set false flag to keep // empty ranges). auto relevantIdRanges = Comparison != CompOp::EQ ? getRangesForId(valueIdsInput.begin(), valueIdsInput.end(), - referenceId_, Comparison) + referenceId, Comparison) : getRangesForId(valueIdsInput.begin(), valueIdsInput.end(), - referenceId_, Comparison, false); + referenceId, Comparison, false); // The vector for relevant BlockMetadata values which contain ValueIds // defined as relevant by relevantIdRanges. @@ -312,23 +320,37 @@ bool RelationalExpression::operator==( if (!otherRelational) { return false; } - return referenceId_ == otherRelational->referenceId_; + return rightSideReferenceValue_ == otherRelational->rightSideReferenceValue_; }; //______________________________________________________________________________ template std::unique_ptr RelationalExpression::clone() const { - return std::make_unique>(referenceId_); + return std::make_unique>( + rightSideReferenceValue_); }; //______________________________________________________________________________ template std::string RelationalExpression::asString( [[maybe_unused]] size_t depth) const { + auto referenceValueToString = [](std::stringstream& stream, + const IdOrLocalVocabEntry& referenceValue) { + std::visit( + ad_utility::OverloadCallOperator{ + [&stream](const ValueId& referenceId) { stream << referenceId; }, + [&stream](const LocalVocabEntry& referenceValue) { + stream << referenceValue.toStringRepresentation(); + }}, + referenceValue); + }; + std::stringstream stream; stream << "Prefilter RelationalExpression<" << getRelationalOpStr(Comparison) - << ">\nValueId: " << referenceId_ << std::endl; + << ">\nreferenceValue_ : "; + referenceValueToString(stream, rightSideReferenceValue_); + stream << " ." << std::endl; return stream.str(); }; @@ -456,6 +478,23 @@ template class LogicalExpression; namespace detail { +//______________________________________________________________________________ +// Returns the corresponding mirrored `RelationalExpression` for the given `CompOp comparison` template argument. For +// example, the mirroring procedure will transform the relational expression +// `referenceValue > ?var` into `?var < referenceValue`. +template +static std::unique_ptr makeMirroredExpression( + const IdOrLocalVocabEntry& referenceValue) { + using enum CompOp; + using namespace ad_utility; + using P = std::pair; + constexpr ConstexprMap mirrorMap( + {P{LT, GT}, P{LE, GE}, P{GE, LE}, P{GT, LT}, P{EQ, EQ}, P{NE, NE}}); + return std::make_unique>( + referenceValue); +} + //______________________________________________________________________________ void checkPropertiesForPrefilterConstruction( const std::vector& vec) { @@ -473,5 +512,31 @@ void checkPropertiesForPrefilterConstruction( } } +//______________________________________________________________________________ +template +std::vector makePrefilterExpressionVec( + const IdOrLocalVocabEntry& referenceValue, const Variable& variable, + const bool mirrored) { + std::vector resVec{}; + resVec.emplace_back( + mirrored + ? makeMirroredExpression(referenceValue) + : std::make_unique>(referenceValue), + variable); + return resVec; +} + +//______________________________________________________________________________ +#define INSTANTIATE_MAKE_PREFILTER(Comparison) \ + template std::vector \ + makePrefilterExpressionVec(const IdOrLocalVocabEntry&, \ + const Variable&, const bool); +INSTANTIATE_MAKE_PREFILTER(CompOp::LT); +INSTANTIATE_MAKE_PREFILTER(CompOp::LE); +INSTANTIATE_MAKE_PREFILTER(CompOp::GE); +INSTANTIATE_MAKE_PREFILTER(CompOp::GT); +INSTANTIATE_MAKE_PREFILTER(CompOp::EQ); +INSTANTIATE_MAKE_PREFILTER(CompOp::NE); + } // namespace detail } // namespace prefilterExpressions diff --git a/src/engine/sparqlExpressions/PrefilterExpressionIndex.h b/src/engine/sparqlExpressions/PrefilterExpressionIndex.h index 8b73a720ca..73f11e0409 100644 --- a/src/engine/sparqlExpressions/PrefilterExpressionIndex.h +++ b/src/engine/sparqlExpressions/PrefilterExpressionIndex.h @@ -23,6 +23,8 @@ namespace prefilterExpressions { +using IdOrLocalVocabEntry = std::variant; + //______________________________________________________________________________ // The maximum recursion depth for `info()` / `operator<<()`. A depth of `3` // should be sufficient for most `PrefilterExpressions` in our use case. @@ -101,16 +103,21 @@ class PrefilterExpression { return str; } + // Static helper to retrieve the reference `ValueId` from the + // `IdOrLocalVocabEntry` variant. + static ValueId getValueIdFromIdOrLocalVocabEntry( + const IdOrLocalVocabEntry& refernceValue, LocalVocab& vocab); + private: - // Performs the following conditional checks on the provided `BlockMetadata` - // values: - // (1) unqiueness of blocks - // (2) sorted (order) - // (3) Constant values for all columns `< evaluationColumn` - // This function subsequently invokes the `evaluateImpl` method and - // checks the corresponding result for those conditions again. - // If a respective condition is violated, the function performing the checks - // will throw a `std::runtime_error`. + // Note: Use `evaluate` for general evaluation of `PrefilterExpression` + // instead of this method. + // Performs the following conditional checks on + // the provided `BlockMetadata` values: (1) unqiueness of blocks (2) sorted + // (order) (3) Constant values for all columns `< evaluationColumn` This + // function subsequently invokes the `evaluateImpl` method and checks the + // corresponding result for those conditions again. If a respective condition + // is violated, the function performing the checks will throw a + // `std::runtime_error`. std::vector evaluateAndCheckImpl( std::span input, size_t evaluationColumn) const; @@ -130,12 +137,18 @@ using CompOp = valueIdComparators::Comparison; template class RelationalExpression : public PrefilterExpression { private: - // The ValueId on which we perform the relational comparison on. - ValueId referenceId_; + // This is the right hand side value of the relational expression. The left + // hand value is indirectly supplied during the evaluation process via the + // `evaluationColumn` argument. `evaluationColumn` represents the column index + // associated with the `Variable` column of the `IndexScan`. + // E.g., a less-than expression with a value of 3 will represent the logical + // relation ?var < 3. A equal-to expression with a value of "Freiburg" will + // represent ?var = "Freiburg". + IdOrLocalVocabEntry rightSideReferenceValue_; public: - explicit RelationalExpression(const ValueId referenceId) - : referenceId_(referenceId) {} + explicit RelationalExpression(const IdOrLocalVocabEntry& referenceValue) + : rightSideReferenceValue_(referenceValue) {} std::unique_ptr logicalComplement() const override; bool operator==(const PrefilterExpression& other) const override; @@ -239,5 +252,19 @@ using PrefilterExprVariablePair = void checkPropertiesForPrefilterConstruction( const std::vector& vec); +//______________________________________________________________________________ +// Creates a `RelationalExpression` prefilter expression based on +// the templated `CompOp` comparison operation and the reference +// `IdOrLocalVocabEntry` value. With the next step, the corresponding +// `, Variable>` pair is created, and finally +// returned in a vector. The `mirrored` flag indicates if the given +// `RelationalExpression` should be mirrored. The mirroring +// procedure changes the (asymmetrical) comparison operations: +// e.g. `5 < ?x` is changed to `?x > 5`. +template +std::vector makePrefilterExpressionVec( + const IdOrLocalVocabEntry& referenceValue, const Variable& variable, + bool mirrored); + } // namespace detail } // namespace prefilterExpressions diff --git a/src/engine/sparqlExpressions/RelationalExpressions.cpp b/src/engine/sparqlExpressions/RelationalExpressions.cpp index 6e027fac87..5bc36b528e 100644 --- a/src/engine/sparqlExpressions/RelationalExpressions.cpp +++ b/src/engine/sparqlExpressions/RelationalExpressions.cpp @@ -418,58 +418,29 @@ template std::vector RelationalExpression::getPrefilterExpressionForMetadata( [[maybe_unused]] bool isNegated) const { - namespace p = prefilterExpressions; AD_CORRECTNESS_CHECK(children_.size() == 2); const SparqlExpression* child0 = children_.at(0).get(); const SparqlExpression* child1 = children_.at(1).get(); - const auto mirroredExpression = - [](const ValueId valueId) -> std::unique_ptr { - using enum Comparison; - switch (comp) { - case LT: - // Id < ?var -> ?var > Id - return std::make_unique(valueId); - case LE: - // Id <= ?var -> ?var >= Id - return std::make_unique(valueId); - case GE: - // Id >= ?var -> ?var <= Id - return std::make_unique(valueId); - case GT: - // Id > ?var -> ?var < Id - return std::make_unique(valueId); - case EQ: - case NE: - // EQ(==) or NE(!=) - // Given that these two relations are symmetric w.r.t. ?var and Id, - // no swap regarding the relational operator is necessary. - return std::make_unique>(valueId); - default: - // Unchecked / new valueIdComparators::Comparison case. - AD_FAIL(); + const auto tryGetPrefilterExprVariablePairVec = + [](const SparqlExpression* child0, const SparqlExpression* child1, + bool reversed) -> std::vector { + const auto* variableExpr = dynamic_cast(child0); + if (!variableExpr) { + return {}; } - }; - const auto tryGetPrefilterExprVariablePairVec = - [&mirroredExpression](const SparqlExpression* child0, - const SparqlExpression* child1, bool reversed) { - std::vector resVec{}; - if (const auto* variable = - dynamic_cast(child0)) { - if (const auto* valueId = dynamic_cast(child1)) { - resVec.emplace_back( - reversed ? mirroredExpression(valueId->value()) - : std::make_unique>( - valueId->value()), - variable->value()); - } - } - return resVec; - }; + const auto& optReferenceValue = + detail::getIdOrLocalVocabEntryFromLiteralExpression(child1); + if (!optReferenceValue.has_value()) { + return {}; + } + return prefilterExpressions::detail::makePrefilterExpressionVec( + optReferenceValue.value(), variableExpr->value(), reversed); + }; // Option 1: // RelationalExpression containing a VariableExpression as the first child - // and an IdExpression as the second child. + // and an IdExpression, IdExpression or IriExpression as the second child. // E.g. for ?x >= 10 (RelationalExpression Sparql), we obtain the following // pair with PrefilterExpression and Variable: <(>= 10), ?x> auto resVec = tryGetPrefilterExprVariablePairVec(child0, child1, false); @@ -477,9 +448,9 @@ RelationalExpression::getPrefilterExpressionForMetadata( return resVec; } // Option 2: - // RelationalExpression containing an IdExpression as the first child and a - // VariableExpression as the second child. - // (1) 10 >= ?x (RelationalExpression Sparql), we obtain the following + // RelationalExpression containing an IdExpression, LiteralExpression or + // IriExpression as the first child and a VariableExpression as the second + // child. (1) 10 >= ?x (RelationalExpression Sparql), we obtain the following // pair with PrefilterExpression and Variable: <(<= 10), ?x> // (2) 10 != ?x (RelationalExpression Sparql), we obtain the following // pair with PrefilterExpression and Variable: <(!= 10), ?x>; diff --git a/src/engine/sparqlExpressions/StringExpressions.cpp b/src/engine/sparqlExpressions/StringExpressions.cpp index 2392ec2b18..f7e7d9bca7 100644 --- a/src/engine/sparqlExpressions/StringExpressions.cpp +++ b/src/engine/sparqlExpressions/StringExpressions.cpp @@ -244,26 +244,23 @@ class StrStartsExpressionImpl : public NaryExpression { AD_CORRECTNESS_CHECK(this->N == 2); const SparqlExpression* child0 = this->getNthChild(0).value(); const SparqlExpression* child1 = this->getNthChild(1).value(); - const auto getPrefilterExprVariableVec = [](const SparqlExpression* child0, - const SparqlExpression* child1, - bool startsWithVar) { - using namespace prefilterExpressions; - std::vector resVec{}; - if (const auto* variable = - dynamic_cast(child0)) { - if (const auto* valueId = dynamic_cast(child1)) { - !startsWithVar - // Will return: {<(>= VocabId(n)), ?var>} (Option 1) - ? resVec.emplace_back( - std::make_unique(valueId->value()), - variable->value()) - // Will return: {<(<= VocabId(n)), ?var>} (Option 2) - : resVec.emplace_back( - std::make_unique(valueId->value()), - variable->value()); - } + + const auto getPrefilterExprVariableVec = + [](const SparqlExpression* child0, const SparqlExpression* child1, + bool startsWithVar) -> std::vector { + const auto* varExpr = dynamic_cast(child0); + if (!varExpr) { + return {}; } - return resVec; + + const auto& optReferenceValue = + getIdOrLocalVocabEntryFromLiteralExpression(child1, true); + if (optReferenceValue.has_value()) { + return prefilterExpressions::detail::makePrefilterExpressionVec< + prefilterExpressions::CompOp::GE>(optReferenceValue.value(), + varExpr->value(), startsWithVar); + } + return {}; }; // Remark: With the current implementation we only prefilter w.r.t. one // bound. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6f8aa447e7..9dd3a733a9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -307,7 +307,7 @@ addLinkAndDiscoverTest(AlgorithmTest) addLinkAndDiscoverTestSerial(CompressedRelationsTest index) -addLinkAndDiscoverTestSerial(PrefilterExpressionIndexTest sparqlExpressions sparqlExpressions parser index) +addLinkAndDiscoverTestSerial(PrefilterExpressionIndexTest engine) addLinkAndDiscoverTestSerial(GetPrefilterExpressionFromSparqlExpressionTest sparqlExpressions index) diff --git a/test/GetPrefilterExpressionFromSparqlExpressionTest.cpp b/test/GetPrefilterExpressionFromSparqlExpressionTest.cpp index d154f856c5..b5312ee8b0 100644 --- a/test/GetPrefilterExpressionFromSparqlExpressionTest.cpp +++ b/test/GetPrefilterExpressionFromSparqlExpressionTest.cpp @@ -176,14 +176,21 @@ TEST(GetPrefilterExpressionFromSparqlExpression, evalAndEqualityCheck( andSprqlExpr(geSprql(varX, IntId(10)), neqSprql(varX, IntId(20))), pr(andExpr(ge(IntId(10)), neq(IntId(20))), varX)); - // ?z > VocabId(0) AND ?y > 0 AND ?x < 30.00 + // ?x >= "berlin" AND ?x != "hamburg" + // expected prefilter pairs: + // {<((>= "berlin") AND (!= "hamburg")), ?x>} + evalAndEqualityCheck( + andSprqlExpr(geSprql(varX, L("\"berlin\"")), + neqSprql(varX, L("\"hamburg\""))), + pr(andExpr(ge(LVE("\"berlin\"")), neq(LVE("\"hamburg\""))), varX)); + // ?z > AND ?y > 0 AND ?x < 30.00 // expected prefilter pairs - // {<(< 30.00), ?x>, <(> 0), ?y>, <(> VocabId(0)), ?z>} - evalAndEqualityCheck(andSprqlExpr(andSprqlExpr(gtSprql(varZ, VocabId(0)), + // {<(< 30.00), ?x>, <(> 0), ?y>, <(> ), ?z>} + evalAndEqualityCheck(andSprqlExpr(andSprqlExpr(gtSprql(varZ, I("")), gtSprql(varY, IntId(0))), ltSprql(varX, DoubleId(30.00))), pr(lt(DoubleId(30.00)), varX), pr(gt(IntId(0)), varY), - pr(gt(VocabId(0)), varZ)); + pr(gt(LVE("")), varZ)); // ?x == VocabId(10) AND ?y >= VocabId(10) // expected prefilter pairs: @@ -212,21 +219,23 @@ TEST(GetPrefilterExpressionFromSparqlExpression, neqSprql(DoubleId(22.1), varY)), pr(eq(VocabId(10)), varX), pr(neq(DoubleId(22.1)), varY), pr(eq(VocabId(0)), varZ)); - // (?z >= 1000 AND ?x == VocabId(10)) OR ?z >= 10000 + // (?z >= 1000 AND ?x == "hamburg") OR ?z >= 10000 // expected prefilter pairs: // {<((>=1000) OR (>= 10000)), ?z>} - evalAndEqualityCheck(orSprqlExpr(andSprqlExpr(geSprql(varZ, IntId(1000)), - eqSprql(varX, VocabId(10))), - geSprql(varZ, IntId(10000))), - pr(orExpr(ge(IntId(1000)), ge(IntId(10000))), varZ)); - // !((?z <= VocabId(10) OR ?y <= VocabId(10)) OR ?x <= VocabId(10)) + evalAndEqualityCheck( + orSprqlExpr(andSprqlExpr(geSprql(varZ, IntId(1000)), + eqSprql(varX, L("\"hamburg\""))), + geSprql(varZ, IntId(10000))), + pr(orExpr(ge(IntId(1000)), ge(IntId(10000))), varZ)); + // !((?z <= VocabId(10) OR ?y <= "world") OR ?x <= VocabId(10)) // expected prefilter pairs: // {, , } evalAndEqualityCheck( - notSprqlExpr(orSprqlExpr( - orSprqlExpr(leSprql(varZ, VocabId(10)), leSprql(varY, VocabId(10))), - leSprql(varX, VocabId(10)))), - pr(notExpr(le(VocabId(10))), varX), pr(notExpr(le(VocabId(10))), varY), + notSprqlExpr(orSprqlExpr(orSprqlExpr(leSprql(varZ, VocabId(10)), + leSprql(varY, L("\"world\""))), + leSprql(varX, VocabId(10)))), + pr(notExpr(le(VocabId(10))), varX), + pr(notExpr(le(LVE("\"world\""))), varY), pr(notExpr(le(VocabId(10))), varZ)); // ?x >= 10 AND ?y >= 10 // expected prefilter pairs: @@ -259,16 +268,16 @@ TEST(GetPrefilterExpressionFromSparqlExpression, leSprql(varY, IntId(0))))), pr(orExpr(notExpr(ge(IntId(10))), notExpr(le(IntId(0)))), varX), pr(orExpr(notExpr(ge(IntId(10))), notExpr(le(IntId(0)))), varY)); - // !(?x == VocabId(10) OR ?x == VocabId(20)) AND !(?z >= 10.00 OR ?y == false) + // !(?x == OR ?x == ) AND !(?z >= 10.00 OR ?y == false) // expected prefilter pairs: - // {, , + // {) OR (== )), ?x>, , // = 10), ?z>} evalAndEqualityCheck( - andSprqlExpr(notSprqlExpr(orSprqlExpr(eqSprql(varX, VocabId(10)), - eqSprql(varX, VocabId(20)))), + andSprqlExpr(notSprqlExpr(orSprqlExpr(eqSprql(varX, I("")), + eqSprql(varX, I("")))), notSprqlExpr(orSprqlExpr(geSprql(varZ, DoubleId(10)), eqSprql(varY, BoolId(false))))), - pr(notExpr(orExpr(eq(VocabId(10)), eq(VocabId(20)))), varX), + pr(notExpr(orExpr(eq(LVE("")), eq(LVE("")))), varX), pr(notExpr(eq(BoolId(false))), varY), pr(notExpr(ge(DoubleId(10))), varZ)); // !(!(?x >= 10 AND ?y >= 10)) OR !(!(?x <= 0 AND ?y <= 0)) @@ -295,15 +304,15 @@ TEST(GetPrefilterExpressionFromSparqlExpression, pr(notExpr(orExpr(andExpr(ge(VocabId(0)), le(VocabId(10))), notExpr(neq(VocabId(99))))), varX)); - // !((?y >= 10 AND ?y <= 100) OR !(?x >= VocabId(99))) + // !((?y >= VocabId(0) AND ?y <= "W") OR !(?x >= )) // expected prefilter pairs: - // {= VocabId(0)) AND (<= VocabId(10)), ?y>, = VocabId(99))), ?x>} + // {= VocabId(0)) AND (<= "W"), ?y>, = )), ?x>} evalAndEqualityCheck( notSprqlExpr(orSprqlExpr( - andSprqlExpr(geSprql(varY, VocabId(0)), leSprql(varY, VocabId(10))), - notSprqlExpr(geSprql(varX, VocabId(99))))), - pr(notExpr(notExpr(ge(VocabId(99)))), varX), - pr(notExpr(andExpr(ge(VocabId(0)), le(VocabId(10)))), varY)); + andSprqlExpr(geSprql(varY, VocabId(0)), leSprql(varY, L("\"W\""))), + notSprqlExpr(geSprql(varX, I(""))))), + pr(notExpr(notExpr(ge(LVE("")))), varX), + pr(notExpr(andExpr(ge(VocabId(0)), le(LVE("\"W\"")))), varY)); // ?z >= 10 AND ?z <= 100 AND ?x >= 10 AND ?x != 50 AND !(?y <= 10) AND // !(?city <= VocabId(1000) OR ?city == VocabId(1005)) // expected prefilter pairs: @@ -363,8 +372,6 @@ TEST(GetPrefilterExpressionFromSparqlExpression, const Iri iri = I(""); const Literal lit = L("\"lit\""); evalAndEqualityCheck(leSprql(var, var)); - evalAndEqualityCheck(neqSprql(iri, var)); - evalAndEqualityCheck(eqSprql(var, iri)); evalAndEqualityCheck(neqSprql(IntId(10), DoubleId(23.3))); evalAndEqualityCheck(gtSprql(DoubleId(10), lit)); evalAndEqualityCheck(ltSprql(VocabId(10), BoolId(10))); @@ -467,10 +474,12 @@ TEST(GetPrefilterExpressionFromSparqlExpression, getPrefilterExprForStrStartsExpr) { const auto varX = Variable{"?x"}; const auto varY = Variable{"?y"}; - evalAndEqualityCheck(strStartsSprql(varX, VocabId(0)), - pr(ge(VocabId(0)), varX)); - evalAndEqualityCheck(strStartsSprql(VocabId(0), varX), - pr(le(VocabId(0)), varX)); + evalAndEqualityCheck(strStartsSprql(varX, L("\"de\"")), + pr(ge(LVE("\"de\"")), varX)); + evalAndEqualityCheck(strStartsSprql(L("\"\""), varX), + pr(le(LVE("\"\"")), varX)); + evalAndEqualityCheck(strStartsSprql(varX, IntId(33))); + evalAndEqualityCheck(strStartsSprql(DoubleId(0.001), varY)); evalAndEqualityCheck(strStartsSprql(varX, varY)); evalAndEqualityCheck(strStartsSprql(VocabId(0), VocabId(10))); } diff --git a/test/PrefilterExpressionIndexTest.cpp b/test/PrefilterExpressionIndexTest.cpp index bc6e7d17d0..2b31304d4f 100644 --- a/test/PrefilterExpressionIndexTest.cpp +++ b/test/PrefilterExpressionIndexTest.cpp @@ -21,6 +21,9 @@ namespace { using namespace prefilterExpressions; using namespace makeFilterExpression; +using namespace filterHelper; + +constexpr auto getId = PrefilterExpression::getValueIdFromIdOrLocalVocabEntry; //______________________________________________________________________________ /* @@ -49,12 +52,32 @@ const Id GraphId = VocabId(0); //______________________________________________________________________________ class PrefilterExpressionOnMetadataTest : public ::testing::Test { public: + // Not directly used. However, given that we depend on LocalVocab values + // during evaluation an active Index + global vocabulary is required. + QueryExecutionContext* qet = ad_utility::testing::getQec(); + LocalVocab vocab{}; const Id referenceDate1 = DateId(DateParser, "1999-11-11"); const Id referenceDate2 = DateId(DateParser, "2005-02-27"); const Id undef = Id::makeUndefined(); const Id falseId = BoolId(false); const Id trueId = BoolId(true); const Id referenceDateEqual = DateId(DateParser, "2000-01-01"); + const LocalVocabEntry augsburg = LVE("\"Augsburg\""); + const LocalVocabEntry berlin = LVE("\"Berlin\""); + const LocalVocabEntry düsseldorf = LVE("\"Düsseldorf\""); + const LocalVocabEntry frankfurt = LVE("\"Frankfurt\""); + const LocalVocabEntry hamburg = LVE("\"Hamburg\""); + const LocalVocabEntry köln = LVE("\"Köln\""); + const LocalVocabEntry münchen = LVE("\"München\""); + const LocalVocabEntry stuttgart = LVE("\"Stuttgart\""); + const Id idAugsburg = getId(augsburg, vocab); + const Id idBerlin = getId(berlin, vocab); + const Id idDüsseldorf = getId(düsseldorf, vocab); + const Id idFrankfurt = getId(frankfurt, vocab); + const Id idHamburg = getId(hamburg, vocab); + const Id idKöln = getId(köln, vocab); + const Id idMünchen = getId(münchen, vocab); + const Id idStuttgart = getId(stuttgart, vocab); // Define BlockMetadata const BlockMetadata b1 = makeBlock(undef, undef); @@ -80,12 +103,12 @@ class PrefilterExpressionOnMetadataTest : public ::testing::Test { const BlockMetadata b15 = makeBlock(DoubleId(-1.23), DoubleId(-6.25)); const BlockMetadata b16 = makeBlock(DoubleId(-6.25), DoubleId(-6.25)); const BlockMetadata b17 = makeBlock(DoubleId(-10.42), DoubleId(-12.00)); - const BlockMetadata b18 = makeBlock(DoubleId(-14.01), VocabId(0)); - const BlockMetadata b19 = makeBlock(VocabId(10), VocabId(14)); - const BlockMetadata b20 = makeBlock(VocabId(14), VocabId(14)); - const BlockMetadata b21 = makeBlock(VocabId(14), VocabId(17)); + const BlockMetadata b18 = makeBlock(DoubleId(-14.01), idAugsburg); + const BlockMetadata b19 = makeBlock(idDüsseldorf, idHamburg); + const BlockMetadata b20 = makeBlock(idHamburg, idHamburg); + const BlockMetadata b21 = makeBlock(idHamburg, idMünchen); const BlockMetadata b22 = - makeBlock(VocabId(20), DateId(DateParser, "1999-12-12")); + makeBlock(idStuttgart, DateId(DateParser, "1999-12-12")); const BlockMetadata b23 = makeBlock(DateId(DateParser, "2000-01-01"), DateId(DateParser, "2000-01-01")); const BlockMetadata b24 = @@ -228,9 +251,10 @@ TEST_F(PrefilterExpressionOnMetadataTest, testBlockFormatForDebugging) { "V:0\n(last) Triple: V:10 D:33.000000 D:2.000000 V:0\nnum. rows: " "0.\n")); EXPECT_THAT( - b21, matcher("#BlockMetadata\n(first) Triple: V:10 D:33.000000 V:14 " - "V:0\n(last) Triple: V:10 D:33.000000 V:17 V:0\nnum. rows: " - "0.\n")); + b21, + matcher("#BlockMetadata\n(first) Triple: V:10 D:33.000000 L:\"Hamburg\" " + "V:0\n(last) Triple: V:10 D:33.000000 L:\"M\xC3\xBCnchen\" " + "V:0\nnum. rows: 0.\n")); auto blockWithGraphInfo = b21; blockWithGraphInfo.graphInfo_.emplace({IntId(12), IntId(13)}); @@ -250,10 +274,10 @@ TEST_F(PrefilterExpressionOnMetadataTest, testLessThanExpressions) { makeTest(lt(DoubleId(-14.01)), {b18}); makeTest(lt(DoubleId(-11.22)), {b17, b18}, true); makeTest(lt(DoubleId(-4.121)), {b9, b15, b16, b17, b18}); - makeTest(lt(VocabId(0)), {b18}); - makeTest(lt(VocabId(12)), {b18, b19}); - makeTest(lt(VocabId(14)), {b18, b19}, true); - makeTest(lt(VocabId(16)), {b18, b19, b20, b21}); + makeTest(lt(augsburg), {b18}); + makeTest(lt(frankfurt), {b18, b19}); + makeTest(lt(hamburg), {b18, b19}, true); + makeTest(lt(münchen), {b18, b19, b20, b21}); makeTest(lt(IntId(100)), {b5, b6, b7, b8, b9, b10, b12, b13, b14, b15, b16, b17, b18}); makeTest(lt(undef), {}); @@ -281,9 +305,9 @@ TEST_F(PrefilterExpressionOnMetadataTest, testLessEqualExpressions) { {b5, b6, b9, b10, b11, b12, b15, b16, b17, b18}); makeTest(le(DoubleId(-11.99999999999999)), {b17, b18}, true); makeTest(le(DoubleId(-14.03)), {b18}); - makeTest(le(VocabId(0)), {b18}); - makeTest(le(VocabId(11)), {b18, b19}); - makeTest(le(VocabId(14)), {b18, b19, b20, b21}, true); + makeTest(le(LVE("\"Aachen\"")), {b18}); + makeTest(le(frankfurt), {b18, b19}); + makeTest(le(hamburg), {b18, b19, b20, b21}, true); makeTest(le(undef), {}); makeTest(le(falseId), {b2, b3}); makeTest(le(trueId), {b2, b3, b4}, true); @@ -308,9 +332,9 @@ TEST_F(PrefilterExpressionOnMetadataTest, testGreaterThanExpression) { makeTest(gt(IntId(4)), {b6, b7, b8, b11, b14}); makeTest(gt(IntId(-4)), {b5, b6, b7, b8, b11, b12, b13, b14, b15}); makeTest(gt(IntId(33)), {}); - makeTest(gt(VocabId(22)), {b22}); - makeTest(gt(VocabId(14)), {b21, b22}, true); - makeTest(gt(VocabId(12)), {b19, b20, b21, b22}); + makeTest(gt(stuttgart), {b22}); + makeTest(gt(hamburg), {b21, b22}, true); + makeTest(gt(berlin), {b19, b20, b21, b22}); makeTest(gt(undef), {}, true); makeTest(gt(falseId), {b4}, true); makeTest(gt(trueId), {}); @@ -338,9 +362,9 @@ TEST_F(PrefilterExpressionOnMetadataTest, testGreaterEqualExpression) { {b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18}); makeTest(ge(DoubleId(7.999999)), {b8, b11, b14}); makeTest(ge(DoubleId(10.0001)), {}); - makeTest(ge(VocabId(14)), {b18, b19, b20, b21, b22}, true); - makeTest(ge(VocabId(10)), {b18, b19, b20, b21, b22}); - makeTest(ge(VocabId(17)), {b18, b21, b22}); + makeTest(ge(hamburg), {b18, b19, b20, b21, b22}, true); + makeTest(ge(düsseldorf), {b18, b19, b20, b21, b22}); + makeTest(ge(münchen), {b18, b21, b22}); makeTest(ge(undef), {}, true); makeTest(ge(falseId), {b2, b3, b4}, true); makeTest(ge(trueId), {b4}); @@ -364,10 +388,10 @@ TEST_F(PrefilterExpressionOnMetadataTest, testEqualExpression) { makeTest(eq(IntId(2)), {b6, b11, b12}, true); makeTest(eq(DoubleId(5.5)), {b7, b11, b14}); makeTest(eq(DoubleId(1.5)), {b6, b11}); - makeTest(eq(VocabId(1)), {b18}); - makeTest(eq(VocabId(14)), {b18, b19, b20, b21}, true); - makeTest(eq(VocabId(11)), {b18, b19}); - makeTest(eq(VocabId(17)), {b18, b21}); + makeTest(eq(berlin), {b18}); + makeTest(eq(hamburg), {b18, b19, b20, b21}, true); + makeTest(eq(frankfurt), {b18, b19}); + makeTest(eq(köln), {b18, b21}); makeTest(eq(IntId(-4)), {b10, b11, b15}, true); makeTest(eq(trueId), {b4}); makeTest(eq(referenceDate1), {b22}); @@ -397,10 +421,10 @@ TEST_F(PrefilterExpressionOnMetadataTest, testNotEqualExpression) { makeTest(neq(DoubleId(-101.23)), {b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18}, true); - makeTest(neq(VocabId(0)), {b19, b20, b21, b22}); - makeTest(neq(VocabId(7)), {b18, b19, b20, b21, b22}, true); - makeTest(neq(VocabId(14)), {b18, b19, b21, b22}); - makeTest(neq(VocabId(17)), {b18, b19, b20, b21, b22}); + makeTest(neq(augsburg), {b19, b20, b21, b22}); + makeTest(neq(berlin), {b18, b19, b20, b21, b22}, true); + makeTest(neq(hamburg), {b18, b19, b21, b22}); + makeTest(neq(münchen), {b18, b19, b20, b21, b22}); makeTest(neq(undef), {}); makeTest(neq(falseId), {b4}, true); makeTest(neq(referenceDateEqual), {b22, b24}); @@ -413,14 +437,13 @@ TEST_F(PrefilterExpressionOnMetadataTest, testNotEqualExpression) { // Note: the `makeTest` function automatically adds the blocks with mixed // datatypes to the expected result. TEST_F(PrefilterExpressionOnMetadataTest, testAndExpression) { - makeTest(andExpr(ge(VocabId(10)), gt(VocabId(10))), {b19, b20, b21, b22}); - makeTest(andExpr(ge(VocabId(10)), ge(VocabId(10))), {b19, b20, b21, b22}, - true); - makeTest(andExpr(ge(VocabId(12)), gt(VocabId(17))), {b22}); - makeTest(andExpr(ge(VocabId(12)), gt(VocabId(17))), {b22}, true); - makeTest(andExpr(ge(VocabId(10)), lt(VocabId(14))), {b19}, true); - makeTest(andExpr(le(VocabId(0)), lt(VocabId(10))), {b18}); - makeTest(andExpr(le(VocabId(17)), lt(VocabId(17))), {b18, b19, b20, b21}); + makeTest(andExpr(ge(düsseldorf), gt(düsseldorf)), {b19, b20, b21, b22}); + makeTest(andExpr(ge(düsseldorf), ge(düsseldorf)), {b19, b20, b21, b22}, true); + makeTest(andExpr(ge(frankfurt), gt(münchen)), {b22}); + makeTest(andExpr(ge(frankfurt), gt(münchen)), {b22}, true); + makeTest(andExpr(ge(düsseldorf), lt(hamburg)), {b19}, true); + makeTest(andExpr(le(augsburg), lt(düsseldorf)), {b18}); + makeTest(andExpr(le(münchen), lt(münchen)), {b18, b19, b20, b21}); makeTest(andExpr(ge(DoubleId(-6.25)), lt(IntId(-7))), {}); makeTest(andExpr(gt(DoubleId(-6.25)), lt(DoubleId(-6.25))), {}); makeTest(andExpr(gt(IntId(0)), lt(IntId(0))), {}); @@ -453,13 +476,13 @@ TEST_F(PrefilterExpressionOnMetadataTest, testAndExpression) { // Note: the `makeTest` function automatically adds the blocks with mixed // datatypes to the expected result. TEST_F(PrefilterExpressionOnMetadataTest, testOrExpression) { - makeTest(orExpr(lt(VocabId(22)), le(VocabId(0))), {b18, b19, b20, b21}); - makeTest(orExpr(le(VocabId(0)), ge(VocabId(16))), {b18, b21, b22}); - makeTest(orExpr(gt(VocabId(17)), ge(VocabId(17))), {b21, b22}); - makeTest(orExpr(lt(DoubleId(-5.95)), eq(VocabId(14))), + makeTest(orExpr(lt(stuttgart), le(augsburg)), {b18, b19, b20, b21}); + makeTest(orExpr(le(augsburg), ge(köln)), {b18, b21, b22}); + makeTest(orExpr(gt(münchen), ge(münchen)), {b21, b22}); + makeTest(orExpr(lt(DoubleId(-5.95)), eq(hamburg)), {b9, b15, b16, b17, b18, b19, b20, b21}); - makeTest(orExpr(eq(DoubleId(0)), neq(VocabId(14))), - {b5, b6, b11, b18, b19, b21}, true); + makeTest(orExpr(eq(DoubleId(0)), neq(hamburg)), {b5, b6, b11, b18, b19, b21}, + true); makeTest(orExpr(eq(DoubleId(0)), eq(DoubleId(-6.25))), {b5, b6, b11, b15, b16, b18}, true); makeTest(orExpr(gt(undef), le(IntId(-6))), {b9, b15, b16, b17, b18}); @@ -467,8 +490,8 @@ TEST_F(PrefilterExpressionOnMetadataTest, testOrExpression) { makeTest(orExpr(eq(IntId(0)), orExpr(lt(IntId(-10)), gt(IntId(8)))), {b5, b6, b8, b11, b14, b17, b18}, true); makeTest(orExpr(gt(referenceDate2), eq(trueId)), {b4}); - makeTest(orExpr(eq(VocabId(17)), orExpr(lt(VocabId(0)), gt(VocabId(20)))), - {b21, b22}, true); + makeTest(orExpr(eq(münchen), orExpr(lt(augsburg), gt(stuttgart))), {b21, b22}, + true); makeTest(orExpr(eq(undef), gt(referenceDateEqual)), {b24}); makeTest(orExpr(gt(IntId(8)), gt(DoubleId(22.1))), {b8, b14}); makeTest(orExpr(lt(DoubleId(-8.25)), le(IntId(-10))), {b9, b17, b18}, true); @@ -482,7 +505,7 @@ TEST_F(PrefilterExpressionOnMetadataTest, testOrExpression) { orExpr(eq(DoubleId(-6.25)), lt(DoubleId(-12)))), {b4, b5, b6, b7, b11, b14, b15, b16, b18}); makeTest(orExpr(le(trueId), gt(falseId)), {b2, b3, b4}, true); - makeTest(orExpr(eq(VocabId(0)), eq(DoubleId(0.25))), {b6, b11, b18}, true); + makeTest(orExpr(eq(augsburg), eq(DoubleId(0.25))), {b6, b11, b18}, true); } //______________________________________________________________________________ @@ -490,10 +513,10 @@ TEST_F(PrefilterExpressionOnMetadataTest, testOrExpression) { // Note: the `makeTest` function automatically adds the blocks with mixed // datatypes to the expected result. TEST_F(PrefilterExpressionOnMetadataTest, testNotExpression) { - makeTest(notExpr(eq(VocabId(2))), {b18, b19, b20, b21, b22}, true); - makeTest(notExpr(eq(VocabId(14))), {b18, b19, b21, b22}); - makeTest(notExpr(neq(VocabId(14))), {b19, b20, b21}, true); - makeTest(notExpr(gt(VocabId(2))), {b18}); + makeTest(notExpr(eq(berlin)), {b18, b19, b20, b21, b22}, true); + makeTest(notExpr(eq(hamburg)), {b18, b19, b21, b22}); + makeTest(notExpr(neq(hamburg)), {b19, b20, b21}, true); + makeTest(notExpr(gt(berlin)), {b18}); makeTest(notExpr(lt(DoubleId(-14.01))), {b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18}); makeTest(notExpr(ge(DoubleId(-14.01))), {b18}); @@ -512,7 +535,7 @@ TEST_F(PrefilterExpressionOnMetadataTest, testNotExpression) { makeTest(notExpr(notExpr(eq(IntId(0)))), {b4, b5, b6, b11}, true); makeTest(notExpr(notExpr(neq(DoubleId(-6.25)))), {b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b17, b18}); - makeTest(notExpr(notExpr(lt(VocabId(10)))), {b18}); + makeTest(notExpr(notExpr(lt(düsseldorf))), {b18}); makeTest(notExpr(notExpr(ge(DoubleId(3.99)))), {b6, b7, b8, b11, b13, b14}, true); makeTest(notExpr(andExpr(le(IntId(0)), ge(IntId(0)))), @@ -528,11 +551,11 @@ TEST_F(PrefilterExpressionOnMetadataTest, testNotExpression) { {b6, b7, b11, b12, b13, b14}, true); makeTest(notExpr(orExpr(ge(DoubleId(0)), gt(IntId(-10)))), {b9, b11, b17, b18}, true); - makeTest(notExpr(orExpr(lt(VocabId(10)), gt(VocabId(10)))), {b19}); + makeTest(notExpr(orExpr(lt(düsseldorf), gt(düsseldorf))), {b19}); makeTest(notExpr(orExpr(lt(DoubleId(-4)), gt(IntId(-4)))), {b10, b11, b15}, true); - makeTest(notExpr(orExpr(gt(IntId(-42)), ge(VocabId(0)))), {b11}, true); - makeTest(notExpr(orExpr(ge(VocabId(14)), gt(VocabId(15)))), {b18, b19}); + makeTest(notExpr(orExpr(gt(IntId(-42)), ge(augsburg))), {b11}, true); + makeTest(notExpr(orExpr(ge(hamburg), gt(köln))), {b18, b19}); } //______________________________________________________________________________ @@ -556,13 +579,11 @@ TEST_F(PrefilterExpressionOnMetadataTest, {b10, b11, b15}); makeTest(orExpr(notExpr(andExpr(lt(IntId(10)), gt(IntId(5)))), eq(IntId(0))), {b4, b5, b6, b7, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18}); - makeTest(andExpr(orExpr(gt(VocabId(16)), le(VocabId(5))), gt(DoubleId(7.25))), - {}, true); + makeTest(andExpr(orExpr(gt(köln), le(berlin)), gt(DoubleId(7.25))), {}, true); makeTest(andExpr(lt(falseId), orExpr(lt(IntId(10)), gt(DoubleId(17.25)))), {}); - makeTest( - orExpr(andExpr(gt(VocabId(16)), ge(VocabId(17))), gt(DoubleId(7.25))), - {b8, b14, b18, b21, b22}); + makeTest(orExpr(andExpr(gt(köln), ge(münchen)), gt(DoubleId(7.25))), + {b8, b14, b18, b21, b22}); makeTest(orExpr(eq(trueId), andExpr(gt(referenceDate1), lt(referenceDate2))), {b4, b22, b23}, true); } @@ -615,6 +636,7 @@ TEST_F(PrefilterExpressionOnMetadataTest, testMethodClonePrefilterExpression) { makeTestClone(gt(referenceDate2)); makeTestClone(andExpr(lt(VocabId(20)), gt(VocabId(10)))); makeTestClone(neq(IntId(10))); + makeTestClone(le(LVE("\"Hello World\""))); makeTestClone(orExpr(eq(IntId(10)), neq(DoubleId(10)))); makeTestClone(notExpr(ge(referenceDate1))); makeTestClone(notExpr(notExpr(neq(VocabId(0))))); @@ -625,6 +647,8 @@ TEST_F(PrefilterExpressionOnMetadataTest, testMethodClonePrefilterExpression) { orExpr(gt(DoubleId(0.001)), lt(IntId(250))))); makeTestClone(orExpr(orExpr(eq(VocabId(101)), lt(IntId(100))), notExpr(andExpr(lt(VocabId(0)), neq(IntId(100)))))); + makeTestClone(orExpr(orExpr(le(LVE("")), gt(LVE(""))), + neq(LVE("")))); } //______________________________________________________________________________ @@ -635,16 +659,21 @@ TEST_F(PrefilterExpressionOnMetadataTest, testEqualityOperator) { ASSERT_FALSE(*neq(BoolId(true)) == *eq(BoolId(true))); ASSERT_TRUE(*eq(IntId(1)) == *eq(IntId(1))); ASSERT_TRUE(*ge(referenceDate1) == *ge(referenceDate1)); + ASSERT_TRUE(*eq(LVE("")) == *eq(LVE(""))); + ASSERT_FALSE(*gt(LVE("")) == *gt(LVE("\"iri\""))); // NotExpression ASSERT_TRUE(*notExpr(eq(IntId(0))) == *notExpr(eq(IntId(0)))); ASSERT_TRUE(*notExpr(notExpr(ge(VocabId(0)))) == *notExpr(notExpr(ge(VocabId(0))))); + ASSERT_TRUE(*notExpr(le(LVE(""))) == *notExpr(le(LVE("")))); ASSERT_FALSE(*notExpr(gt(IntId(0))) == *eq(IntId(0))); ASSERT_FALSE(*notExpr(andExpr(eq(IntId(1)), eq(IntId(0)))) == *notExpr(ge(VocabId(0)))); // Binary PrefilterExpressions (AND and OR) ASSERT_TRUE(*orExpr(eq(IntId(0)), le(IntId(0))) == *orExpr(eq(IntId(0)), le(IntId(0)))); + ASSERT_TRUE(*orExpr(lt(LVE("\"L\"")), gt(LVE("\"O\""))) == + *orExpr(lt(LVE("\"L\"")), gt(LVE("\"O\"")))); ASSERT_TRUE(*andExpr(le(VocabId(1)), le(IntId(0))) == *andExpr(le(VocabId(1)), le(IntId(0)))); ASSERT_FALSE(*orExpr(eq(IntId(0)), le(IntId(0))) == @@ -657,29 +686,65 @@ TEST_F(PrefilterExpressionOnMetadataTest, testEqualityOperator) { // Test PrefilterExpression content formatting for debugging. TEST(PrefilterExpressionExpressionOnMetadataTest, checkPrintFormattedPrefilterExpression) { - auto expr = lt(IntId(10)); - EXPECT_EQ((std::stringstream() << *expr).str(), - "Prefilter RelationalExpression\nValueId: I:10\n.\n"); - expr = orExpr(eq(VocabId(0)), eq(VocabId(10))); - EXPECT_EQ((std::stringstream() << *expr).str(), - "Prefilter LogicalExpression\nchild1 {Prefilter " - "RelationalExpression\nValueId: V:0\n}child2 {Prefilter " - "RelationalExpression\nValueId: V:10\n}\n.\n"); - expr = neq(DoubleId(8.21)); - EXPECT_EQ((std::stringstream() << *expr).str(), - "Prefilter RelationalExpression\nValueId: D:8.210000\n.\n"); - expr = notExpr(eq(VocabId(0))); - EXPECT_EQ((std::stringstream() << *expr).str(), - "Prefilter NotExpression:\nchild {Prefilter " - "RelationalExpression\nValueId: V:0\n}\n.\n"); - expr = orExpr(le(IntId(0)), ge(IntId(5))); - EXPECT_EQ((std::stringstream() << *expr).str(), - "Prefilter LogicalExpression\nchild1 {Prefilter " - "RelationalExpression\nValueId: I:0\n}child2 {Prefilter " - "RelationalExpression=)>\nValueId: I:5\n}\n.\n"); - expr = andExpr(lt(IntId(20)), gt(IntId(10))); - EXPECT_EQ((std::stringstream() << *expr).str(), - "Prefilter LogicalExpression\nchild1 {Prefilter " - "RelationalExpression\nValueId: I:20\n}child2 {Prefilter " - "RelationalExpression)>\nValueId: I:10\n}\n.\n"); + auto exprToString = [](const PrefilterExpression& expr) { + return (std::stringstream{} << expr).str(); + }; + + auto matcher = [&exprToString](const std::string& substring) { + return ::testing::ResultOf(exprToString, ::testing::Eq(substring)); + }; + + EXPECT_THAT(*lt(IntId(10)), + matcher("Prefilter RelationalExpression\nreferenceValue_ " + ": I:10 .\n.\n")); + EXPECT_THAT( + *orExpr(eq(VocabId(0)), eq(VocabId(10))), + matcher("Prefilter LogicalExpression\nchild1 {Prefilter " + "RelationalExpression\nreferenceValue_ : V:0 .\n}child2 " + "{Prefilter RelationalExpression\nreferenceValue_ : V:10 " + ".\n}\n.\n")); + EXPECT_THAT( + *neq(DoubleId(8.21)), + matcher("Prefilter RelationalExpression\nreferenceValue_ : " + "D:8.210000 .\n.\n")); + EXPECT_THAT( + *notExpr(eq(VocabId(0))), + matcher("Prefilter NotExpression:\nchild {Prefilter " + "RelationalExpression\nreferenceValue_ : V:0 .\n}\n.\n")); + EXPECT_THAT( + *orExpr(le(IntId(0)), ge(IntId(5))), + matcher("Prefilter LogicalExpression\nchild1 {Prefilter " + "RelationalExpression\nreferenceValue_ : I:0 .\n}child2 " + "{Prefilter RelationalExpression=)>\nreferenceValue_ : I:5 " + ".\n}\n.\n")); + EXPECT_THAT( + *andExpr(lt(IntId(20)), gt(IntId(10))), + matcher("Prefilter LogicalExpression\nchild1 {Prefilter " + "RelationalExpression\nreferenceValue_ : I:20 .\n}child2 " + "{Prefilter RelationalExpression)>\nreferenceValue_ : I:10 " + ".\n}\n.\n")); + EXPECT_THAT(*eq(LVE("\"Sophia\"")), + matcher("Prefilter RelationalExpression\nreferenceValue_ " + ": \"Sophia\" .\n.\n")); + EXPECT_THAT(*neq(LVE("")), + matcher("Prefilter RelationalExpression\nreferenceValue_ " + ": .\n.\n")); + EXPECT_THAT( + *andExpr(orExpr(lt(LVE("\"Bob\"")), ge(LVE("\"Max\""))), + neq(LVE("\"Lars\""))), + matcher( + "Prefilter LogicalExpression\nchild1 {Prefilter " + "LogicalExpression\nchild1 {Prefilter " + "RelationalExpression\nreferenceValue_ : \"Bob\" .\n}child2 " + "{Prefilter RelationalExpression=)>\nreferenceValue_ : \"Max\" " + ".\n}\n}child2 {Prefilter " + "RelationalExpression\nreferenceValue_ : \"Lars\" " + ".\n}\n.\n")); + EXPECT_THAT( + *orExpr(neq(LVE("")), neq(LVE(""))), + matcher( + "Prefilter LogicalExpression\nchild1 {Prefilter " + "RelationalExpression\nreferenceValue_ : " + ".\n}child2 {Prefilter RelationalExpression\nreferenceValue_ " + ": .\n}\n.\n")); } diff --git a/test/PrefilterExpressionTestHelpers.h b/test/PrefilterExpressionTestHelpers.h index 934470bf7a..d6ca3204f4 100644 --- a/test/PrefilterExpressionTestHelpers.h +++ b/test/PrefilterExpressionTestHelpers.h @@ -25,8 +25,8 @@ namespace { //______________________________________________________________________________ // Make RelationalExpression template -auto relExpr = - [](const ValueId& referenceId) -> std::unique_ptr { +auto relExpr = [](const IdOrLocalVocabEntry& referenceId) + -> std::unique_ptr { return std::make_unique(referenceId); }; @@ -68,6 +68,15 @@ constexpr auto orExpr = logExpr; constexpr auto notExpr = notPrefilterExpression; namespace filterHelper { + +//______________________________________________________________________________ +// Create `LocalVocabEntry` / `LiteralOrIri`. +// Note: `Iri` string value must start and end with `<`/`>` and the `Literal` +// value with `'`/`'`. +const auto LVE = [](const std::string& litOrIri) -> LocalVocabEntry { + return LocalVocabEntry::fromStringRepresentation(litOrIri); +}; + //______________________________________________________________________________ // Construct a `PAIR` with the given `PrefilterExpression` and `Variable` value. auto pr =