Skip to content

Commit 623bc59

Browse files
committed
changes for code-review (1)
1 parent 74b7d75 commit 623bc59

8 files changed

+155
-98
lines changed

src/engine/sparqlExpressions/NaryExpressionImpl.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ class NaryExpression : public SparqlExpression {
4141
const VariableToColumnMap& varColMap) const override;
4242

4343
// _________________________________________________________________________
44-
std::optional<SparqlExpression*> getChildAtIndex(
45-
size_t childIndex) const override {
44+
std::optional<SparqlExpression*> getChildAtIndex(size_t childIndex) const {
4645
return childIndex < N ? std::make_optional(children_[childIndex].get())
4746
: std::nullopt;
4847
}

src/engine/sparqlExpressions/PrefilterExpressionIndex.cpp

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ static std::string getRelationalOpStr(const CompOp relOp) {
156156
case GT:
157157
return "GT(>)";
158158
default:
159-
AD_FAIL();
159+
return absl::StrCat("Undefined CompOp value: ", static_cast<int>(relOp),
160+
".");
160161
}
161162
}
162163

@@ -501,11 +502,15 @@ void checkPropertiesForPrefilterConstruction(
501502
}
502503

503504
//______________________________________________________________________________
504-
template <CompOp comparison>
505-
static std::unique_ptr<PrefilterExpression> makePrefilterExpressionYearImpl(
506-
const int year) {
505+
std::unique_ptr<PrefilterExpression> makePrefilterExpressionYearImpl(
506+
CompOp comparison, const int year) {
507507
using GeExpr = GreaterEqualExpression;
508508
using LtExpr = LessThanExpression;
509+
510+
// `getDateId` returns an `Id` containing the smallest possible `Date`
511+
// (`xsd::date`) for which `YEAR(Id) == adjustedYear` is valid. This `Id` acts
512+
// as a reference bound for the actual `DateYearOrDuration` prefiltering
513+
// procedure.
509514
const auto getDateId = [](const int adjustedYear) {
510515
return Id::makeFromDate(DateYearOrDuration(Date(adjustedYear, 0, 0)));
511516
};
@@ -526,42 +531,69 @@ static std::unique_ptr<PrefilterExpression> makePrefilterExpressionYearImpl(
526531
return make<OrExpression>(make<LtExpr>(getDateId(year)),
527532
make<GeExpr>(getDateId(year + 1)));
528533
default:
529-
AD_FAIL();
534+
throw std::runtime_error(
535+
absl::StrCat("Set unkown (relational) comparison operator for "
536+
"the creation of PrefilterExpression on date-values: ",
537+
getRelationalOpStr(comparison)));
530538
}
531539
};
532540

533541
//______________________________________________________________________________
534542
template <CompOp comparison>
535543
static std::unique_ptr<PrefilterExpression> makePrefilterExpressionVecImpl(
536-
const IdOrLocalVocabEntry& referenceValue, bool prefilterDate) {
544+
const IdOrLocalVocabEntry& referenceValue, bool prefilterDateByYear) {
545+
using enum Datatype;
537546
// Standard pre-filtering procedure.
538-
if (!prefilterDate) {
547+
if (!prefilterDateByYear) {
539548
return make<RelationalExpression<comparison>>(referenceValue);
540549
}
541-
550+
// Helper to savely retrieve `ValueId/Id` values from the provided
551+
// `IdOrLocalVocabEntry referenceValue` if contained. Given no `ValueId` is
552+
// contained, a explanatory message per `std::runtime_error` is thrown.
553+
const auto retrieveValueIdOrThrowErr =
554+
[](const IdOrLocalVocabEntry& referenceValue) {
555+
return std::visit(
556+
[]<typename T>(const T& value) -> ValueId {
557+
if constexpr (std::is_same_v<std::decay_t<T>, ValueId>) {
558+
return value;
559+
} else if constexpr (std::is_same_v<std::decay_t<T>,
560+
LocalVocabEntry>) {
561+
throw std::runtime_error(absl::StrCat(
562+
"Provided Literal or Iri with value: ",
563+
value.asLiteralOrIri().toStringRepresentation(),
564+
". This is an invalid reference value for filtering date "
565+
"values over expression YEAR. Please provide an integer "
566+
"value as reference year."));
567+
}
568+
throw std::runtime_error(
569+
"Reference value IdOrLocalVocabEntry contains unknown type.");
570+
},
571+
referenceValue);
572+
};
542573
// Handle year extraction and return a date-value adjusted
543574
// `PrefilterExpression` if possible. Given an unsuitable reference value was
544575
// provided, throw a std::runtime_error with an explanatory message.
545-
const auto retrieveYearIntOrThrowRuntimerErr =
546-
[](const IdOrLocalVocabEntry& referenceValue) {
547-
using enum Datatype;
548-
if (auto* valueId = std::get_if<ValueId>(&referenceValue);
549-
valueId && valueId->getDatatype() == Int) {
550-
return valueId->getInt();
576+
const auto retrieveYearIntOrThrowErr =
577+
[&retrieveValueIdOrThrowErr](const IdOrLocalVocabEntry& referenceValue) {
578+
const ValueId& valueId = retrieveValueIdOrThrowErr(referenceValue);
579+
if (valueId.getDatatype() == Int) {
580+
return valueId.getInt();
551581
}
552-
throw std::runtime_error(
553-
"Pre-filtering DATETIME/DATE values over YEAR failed: requires "
554-
"INTEGER reference value.");
582+
throw std::runtime_error(absl::StrCat(
583+
"Reference value for filtering date values over "
584+
"expression YEAR is of invalid datatype: ",
585+
toString(valueId.getDatatype()),
586+
".\nPlease provide an integer value as reference year."));
555587
};
556-
return makePrefilterExpressionYearImpl<comparison>(
557-
retrieveYearIntOrThrowRuntimerErr(referenceValue));
588+
return makePrefilterExpressionYearImpl(
589+
comparison, retrieveYearIntOrThrowErr(referenceValue));
558590
};
559591

560592
//______________________________________________________________________________
561593
template <CompOp comparison>
562594
std::vector<PrefilterExprVariablePair> makePrefilterExpressionVec(
563595
const IdOrLocalVocabEntry& referenceValue, const Variable& variable,
564-
bool mirrored, bool prefilterDate) {
596+
bool mirrored, bool prefilterDateByYear) {
565597
using enum CompOp;
566598
std::vector<PrefilterExprVariablePair> resVec{};
567599
if (mirrored) {
@@ -573,12 +605,12 @@ std::vector<PrefilterExprVariablePair> makePrefilterExpressionVec(
573605
constexpr ad_utility::ConstexprMap<CompOp, CompOp, 6> mirrorMap(
574606
{P{LT, GT}, P{LE, GE}, P{GE, LE}, P{GT, LT}, P{EQ, EQ}, P{NE, NE}});
575607
resVec.emplace_back(
576-
makePrefilterExpressionVecImpl<mirrorMap.at(comparison)>(referenceValue,
577-
prefilterDate),
608+
makePrefilterExpressionVecImpl<mirrorMap.at(comparison)>(
609+
referenceValue, prefilterDateByYear),
578610
variable);
579611
} else {
580612
resVec.emplace_back(makePrefilterExpressionVecImpl<comparison>(
581-
referenceValue, prefilterDate),
613+
referenceValue, prefilterDateByYear),
582614
variable);
583615
}
584616
return resVec;

src/engine/sparqlExpressions/PrefilterExpressionIndex.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,19 +252,34 @@ using PrefilterExprVariablePair =
252252
void checkPropertiesForPrefilterConstruction(
253253
const std::vector<PrefilterExprVariablePair>& vec);
254254

255+
//______________________________________________________________________________
256+
// Use for testing only. The definition here is necessary to call
257+
// `makePrefilterYearImpl` with an invalid `CompOp` argument given that it is
258+
// internally in use over the `CompOp` save template instantiated
259+
// `makePrefilterExpressionVec`. Use `makePrefilterExpressionVec` to retrieve
260+
// the actual `PrefilterExpression` (with corresponding `Variable`).
261+
std::unique_ptr<PrefilterExpression> makePrefilterExpressionYearImpl(
262+
CompOp comparison, const int year);
263+
255264
//______________________________________________________________________________
256265
// Creates a `RelationalExpression<comparison>` prefilter expression based on
257-
// the templated `CompOp` comparison operation and the reference
266+
// the specified `CompOp` comparison operation and the reference
258267
// `IdOrLocalVocabEntry` value. With the next step, the corresponding
259268
// `<RelationalExpression<comparison>, Variable>` pair is created, and finally
260-
// returned in a vector. The `mirrored` flag indicates if the given
261-
// `RelationalExpression<comparison>` should be mirrored. The mirroring
262-
// procedure changes the (asymmetrical) comparison operations:
263-
// e.g. `5 < ?x` is changed to `?x > 5`.
269+
// returned in a vector.
270+
// The `mirrored` flag indicates if the given `RelationalExpression<comparison>`
271+
// should be mirrored. The mirroring procedure changes the (asymmetrical)
272+
// comparison operations: e.g. `5 < ?x` is changed to `?x > 5`.
273+
// The `prefilterDateByYear` flag indicates that the constructed
274+
// `PrefilterExpression<comp>` needs to consider `Date`/`DateYearOrDuration`
275+
// value ranges for the `BlockMetadata` pre-selection (w.r.t. the year provided
276+
// as an Int-`ValueId` over `referenceValue`). This requires a slightly
277+
// different logic when constructing the expression, hence set
278+
// `prefilterDateByYear` as an indicator.
264279
template <CompOp comparison>
265280
std::vector<PrefilterExprVariablePair> makePrefilterExpressionVec(
266281
const IdOrLocalVocabEntry& referenceValue, const Variable& variable,
267-
bool mirrored, bool prefilterDate = false);
282+
bool mirrored, bool prefilterDateByYear = false);
268283

269284
} // namespace detail
270285
} // namespace prefilterExpressions

src/engine/sparqlExpressions/RelationalExpressions.cpp

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,33 @@ ExpressionResult InExpression::evaluate(
425425
return result;
426426
}
427427

428+
// _____________________________________________________________________________
429+
// (1) the provided `SparqlExpression* child` is a direct `Variable` expression
430+
// (e.g. `?x`), return `<Variable, false>`.
431+
// (2) the provided `SparqlExpression* child` is an expression `YEAR` which
432+
// referes to a `Variable` value (e.g. `YEAR(?x)`), return `<Variable, true>`.
433+
// (3) None of the previous expression cases, return default `std::nullopt`.
434+
// The `bool` flag is relevant later on to differentiate w.r.t. the logic that
435+
// needs to be applied for the creation of `PrefilterExpression`.
436+
static std::optional<std::pair<Variable, bool>> getOptVariableAndIsYear(
437+
const SparqlExpression* child) {
438+
// (1) The direct child already contains the Variable.
439+
if (auto optVariable = child->getVariableOrNullopt(); optVariable) {
440+
return std::make_pair(optVariable.value(), false);
441+
}
442+
if (!child->isYearExpression()) return std::nullopt;
443+
// (2) The direct child is an expression YEAR();
444+
// If possible retrieve the Variable related to YEAR().
445+
const auto& grandChild = child->children();
446+
// The expression YEAR() should by definition hold a single child.
447+
AD_CORRECTNESS_CHECK(grandChild.size() == 1);
448+
if (auto optVariable = grandChild[0]->getVariableOrNullopt(); optVariable) {
449+
return std::make_pair(optVariable.value(), true);
450+
}
451+
// No Variable for pre-filtering available.
452+
return std::nullopt;
453+
}
454+
428455
// _____________________________________________________________________________
429456
template <Comparison comp>
430457
std::vector<PrefilterExprVariablePair>
@@ -434,44 +461,17 @@ RelationalExpression<comp>::getPrefilterExpressionForMetadata(
434461
const SparqlExpression* child0 = children_.at(0).get();
435462
const SparqlExpression* child1 = children_.at(1).get();
436463

437-
const auto getOptVariableAndIsYear = [](const SparqlExpression* child)
438-
-> std::optional<std::pair<Variable, bool>> {
439-
// (1) The direct child already contains the Variable.
440-
if (auto optVariable = child->getVariableOrNullopt(); optVariable) {
441-
return std::make_pair(optVariable.value(), false);
442-
}
443-
// (2) The direct child is an expression YEAR();
444-
// If possible retrieve the Variable related to YEAR().
445-
if (child->isYearExpression()) {
446-
std::optional<SparqlExpression*> optGrandChild =
447-
child->getChildAtIndex(0);
448-
// The expression YEAR() should by definition hold a child.
449-
AD_CORRECTNESS_CHECK(optGrandChild.has_value());
450-
if (auto optVariable = optGrandChild.value()->getVariableOrNullopt();
451-
optVariable) {
452-
return std::make_pair(optVariable.value(), true);
453-
}
454-
}
455-
// No Variable for pre-filtering available.
456-
return std::nullopt;
457-
};
458-
459464
const auto tryGetPrefilterExprVariablePairVec =
460-
[&getOptVariableAndIsYear](
461-
const SparqlExpression* child0, const SparqlExpression* child1,
462-
bool reversed) -> std::vector<PrefilterExprVariablePair> {
463-
if (auto optVariableIsYearPair = getOptVariableAndIsYear(child0);
464-
optVariableIsYearPair) {
465-
const auto& [variable, prefilterDate] = optVariableIsYearPair.value();
466-
const auto& optReferenceValue =
467-
detail::getIdOrLocalVocabEntryFromLiteralExpression(child1);
468-
if (!optReferenceValue.has_value()) {
469-
return {};
470-
}
471-
return prefilterExpressions::detail::makePrefilterExpressionVec<comp>(
472-
optReferenceValue.value(), variable, reversed, prefilterDate);
473-
}
474-
return {};
465+
[](const SparqlExpression* child0, const SparqlExpression* child1,
466+
bool reversed) -> std::vector<PrefilterExprVariablePair> {
467+
const auto& optVariableIsYearPair = getOptVariableAndIsYear(child0);
468+
if (!optVariableIsYearPair.has_value()) return {};
469+
const auto& [variable, prefilterDate] = optVariableIsYearPair.value();
470+
const auto& optReferenceValue =
471+
detail::getIdOrLocalVocabEntryFromLiteralExpression(child1);
472+
if (!optReferenceValue.has_value()) return {};
473+
return prefilterExpressions::detail::makePrefilterExpressionVec<comp>(
474+
optReferenceValue.value(), variable, reversed, prefilterDate);
475475
};
476476
// Option 1:
477477
// RelationalExpression containing a VariableExpression as the first child

src/engine/sparqlExpressions/SparqlExpression.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,6 @@ std::unique_ptr<SparqlExpression> SparqlExpression::replaceChild(
6565
return std::exchange(children()[childIndex], std::move(newExpression));
6666
}
6767

68-
// _____________________________________________________________________________
69-
std::optional<SparqlExpression*> SparqlExpression::getChildAtIndex(
70-
[[maybe_unused]] size_t childIndex) const {
71-
return std::nullopt;
72-
};
73-
7468
// _____________________________________________________________________________
7569
const string& SparqlExpression::descriptor() const { return _descriptor; }
7670

src/engine/sparqlExpressions/SparqlExpression.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,6 @@ class SparqlExpression {
6060
virtual std::unique_ptr<SparqlExpression> replaceChild(
6161
size_t childIndex, std::unique_ptr<SparqlExpression> newExpression);
6262

63-
// Returns the child at index `childIndex` for this expression.
64-
// By default the implementation of this method returns `std::nullopt`.
65-
// If the given `childIndex` is out of bounds for the respective expression,
66-
// `std::nullopt` will be returned as well.
67-
virtual std::optional<SparqlExpression*> getChildAtIndex(
68-
size_t childIndex) const;
69-
7063
// Get a unique identifier for this expression, used as cache key.
7164
virtual string getCacheKey(const VariableToColumnMap& varColMap) const = 0;
7265

test/GetPrefilterExpressionFromSparqlExpressionTest.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -523,24 +523,37 @@ TEST(GetPrefilterExpressionFromSparqlExpression, tryGetPrefilterExprForDate) {
523523
evalAndEqualityCheck(
524524
eqSprql(yearSprqlExpr(ltSprql(var, IntId(2025))), IntId(2025)));
525525

526-
auto assertThrowsError = [](std::unique_ptr<SparqlExpression> expr) {
527-
try {
528-
expr->getPrefilterExpressionForMetadata();
529-
FAIL() << "Expected std::runtime_error";
530-
} catch (const std::runtime_error& err) {
531-
EXPECT_STREQ(err.what(),
532-
"Pre-filtering DATETIME/DATE values over YEAR failed: "
533-
"requires INTEGER reference value.");
534-
} catch (...) {
535-
FAIL() << "Different error to std::runtime_error was thrown.";
536-
}
526+
auto assertThrowsError = [](std::unique_ptr<SparqlExpression> expr,
527+
const std::string& runtimeErrorMessage) {
528+
AD_EXPECT_THROW_WITH_MESSAGE(expr->getPrefilterExpressionForMetadata(),
529+
::testing::Eq(runtimeErrorMessage));
537530
};
538531
// Test SparqlExpressions for which we expect that the reference value-type
539532
// error is thrown.
540-
assertThrowsError(eqSprql(yearSprqlExpr(var), I("<iri>")));
541-
assertThrowsError(gtSprql(yearSprqlExpr(var), I("<iri>")));
542-
assertThrowsError(ltSprql(yearSprqlExpr(var), Id::makeFromBool(false)));
543-
assertThrowsError(neqSprql(yearSprqlExpr(var), Id::makeUndefined()));
533+
assertThrowsError(
534+
eqSprql(yearSprqlExpr(var), I("<iri>")),
535+
"Provided Literal or Iri with value: <iri>. This is an invalid reference "
536+
"value for filtering date values over expression YEAR. Please provide an "
537+
"integer value as reference year.");
538+
assertThrowsError(
539+
gtSprql(yearSprqlExpr(var), I("<iri>")),
540+
"Provided Literal or Iri with value: <iri>. This is an invalid reference "
541+
"value for filtering date values over expression YEAR. Please provide an "
542+
"integer value as reference year.");
543+
assertThrowsError(
544+
neqSprql(yearSprqlExpr(var), L("\"lit value\"")),
545+
"Provided Literal or Iri with value: \"lit value\". This is an invalid "
546+
"reference "
547+
"value for filtering date values over expression YEAR. Please provide an "
548+
"integer value as reference year.");
549+
assertThrowsError(ltSprql(yearSprqlExpr(var), Id::makeFromBool(false)),
550+
"Reference value for filtering date values over expression "
551+
"YEAR is of invalid datatype: Bool.\nPlease provide an "
552+
"integer value as reference year.");
553+
assertThrowsError(neqSprql(yearSprqlExpr(var), Id::makeUndefined()),
554+
"Reference value for filtering date values over expression "
555+
"YEAR is of invalid datatype: Undefined.\nPlease provide "
556+
"an integer value as reference year.");
544557
}
545558

546559
// Test that the conditions required for a correct merge of child

test/PrefilterExpressionIndexTest.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -765,10 +765,9 @@ TEST_F(PrefilterExpressionOnMetadataTest, testEqualityOperator) {
765765
// Test PrefilterExpression content formatting for debugging.
766766
TEST(PrefilterExpressionExpressionOnMetadataTest,
767767
checkPrintFormattedPrefilterExpression) {
768-
auto exprToString = [](const PrefilterExpression& expr) {
768+
auto exprToString = [](const auto& expr) {
769769
return (std::stringstream{} << expr).str();
770770
};
771-
772771
auto matcher = [&exprToString](const std::string& substring) {
773772
return ::testing::ResultOf(exprToString, ::testing::Eq(substring));
774773
};
@@ -827,3 +826,15 @@ TEST(PrefilterExpressionExpressionOnMetadataTest,
827826
".\n}child2 {Prefilter RelationalExpression<NE(!=)>\nreferenceValue_ "
828827
": <iri/custom/v66> .\n}\n.\n"));
829828
}
829+
830+
//______________________________________________________________________________
831+
// Test PrefilterExpression unkown `CompOp comparison` value detection.
832+
TEST(PrefilterExpressionExpressionOnMetadataTest,
833+
checkMakePrefilterVecDetectsAndThrowsForInvalidComparisonOp) {
834+
using namespace prefilterExpressions::detail;
835+
AD_EXPECT_THROW_WITH_MESSAGE(
836+
makePrefilterExpressionYearImpl(static_cast<CompOp>(10), 0),
837+
::testing::HasSubstr(
838+
"Set unkown (relational) comparison operator for the creation of "
839+
"PrefilterExpression on date-values: Undefined CompOp value: 10."));
840+
}

0 commit comments

Comments
 (0)