Skip to content

Commit

Permalink
new LiteralOrIriValueGetter
Browse files Browse the repository at this point in the history
  • Loading branch information
Annika Greif committed Nov 13, 2024
1 parent e73d1ab commit 0ed79df
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 3 deletions.
76 changes: 75 additions & 1 deletion src/engine/ExportQueryExecutionTrees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "util/ConstexprUtils.h"
#include "util/http/MediaTypes.h"

using LiteralOrIri = ad_utility::triple_component::LiteralOrIri;

// __________________________________________________________________________
cppcoro::generator<const IdTable&> ExportQueryExecutionTrees::getIdTables(
const Result& result) {
Expand Down Expand Up @@ -222,11 +224,58 @@ ExportQueryExecutionTrees::idToStringAndTypeForEncodedValue(Id id) {
}
}

// _____________________________________________________________________________
std::optional<LiteralOrIri>
ExportQueryExecutionTrees::idToLiteralOrIriForEncodedValue(Id id) {
using enum Datatype;
auto fromIri = TripleComponent::Iri::fromIrirefWithoutBrackets;
switch (id.getDatatype()) {
case Undefined:
return std::nullopt;
case Double:
// We use the immediately invoked lambda here because putting this block
// in braces confuses the test coverage tool.
return [id]() -> std::optional<LiteralOrIri> {
// Format as integer if fractional part is zero, let C++ decide
// otherwise.
std::stringstream ss;
double d = id.getDouble();
double dIntPart;
if (std::modf(d, &dIntPart) == 0.0) {
ss << std::fixed << std::setprecision(0) << id.getDouble();
} else {
ss << d;
}
return LiteralOrIri::literalWithoutQuotes(
std::move(ss).str(),
TripleComponent::Iri::fromIrirefWithoutBrackets(XSD_DOUBLE_TYPE));
}();
case Bool:
return id.getBool() ? LiteralOrIri::literalWithoutQuotes(
"true", fromIri(XSD_BOOLEAN_TYPE))
: LiteralOrIri::literalWithoutQuotes(
"false", fromIri(XSD_BOOLEAN_TYPE));
case Int:
return LiteralOrIri::literalWithoutQuotes(std::to_string(id.getInt()),
fromIri(XSD_INT_TYPE));
case Date:
return LiteralOrIri::literalWithoutQuotes(
id.getDate().toStringAndType().first, fromIri(XSD_DATE_TYPE));
case GeoPoint:
return LiteralOrIri::literalWithoutQuotes(
id.getGeoPoint().toStringAndType().first, fromIri(GEO_WKT_LITERAL));
case BlankNodeIndex:
return LiteralOrIri::literalWithoutQuotes(
absl::StrCat("_:bn", id.getBlankNodeIndex().get()));
default:
AD_FAIL();
}
}

// _____________________________________________________________________________
ad_utility::triple_component::LiteralOrIri
ExportQueryExecutionTrees::getLiteralOrIriFromVocabIndex(
const Index& index, Id id, const LocalVocab& localVocab) {
using LiteralOrIri = ad_utility::triple_component::LiteralOrIri;
switch (id.getDatatype()) {
case Datatype::LocalVocabIndex:
return localVocab.getWord(id.getLocalVocabIndex()).asLiteralOrIri();
Expand Down Expand Up @@ -287,6 +336,31 @@ ExportQueryExecutionTrees::idToStringAndType(const Index& index, Id id,
return idToStringAndTypeForEncodedValue(id);
}
}

// _____________________________________________________________________________
std::optional<LiteralOrIri> ExportQueryExecutionTrees::idToLiteralOrIri(
const Index& index, Id id, const LocalVocab& localVocab) {
using enum Datatype;
auto handleIriOrLiteral =
[](const LiteralOrIri& word) -> std::optional<LiteralOrIri> {
return word;
};
switch (id.getDatatype()) {
case WordVocabIndex:
// TODO
return std::nullopt;
case VocabIndex:
case LocalVocabIndex:
return handleIriOrLiteral(
getLiteralOrIriFromVocabIndex(index, id, localVocab));
case TextRecordIndex:
// TODO
return std::nullopt;
default:
return idToLiteralOrIriForEncodedValue(id);
}
}

// ___________________________________________________________________________
template std::optional<std::pair<std::string, const char*>>
ExportQueryExecutionTrees::idToStringAndType<true, false, std::identity>(
Expand Down
10 changes: 10 additions & 0 deletions src/engine/ExportQueryExecutionTrees.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ExportQueryExecutionTrees {
public:
using MediaType = ad_utility::MediaType;
using CancellationHandle = ad_utility::SharedCancellationHandle;
using LiteralOrIri = ad_utility::triple_component::LiteralOrIri;

// Compute the result of the given `parsedQuery` (created by the
// `SparqlParser`) for which the `QueryExecutionTree` has been previously
Expand Down Expand Up @@ -84,6 +85,15 @@ class ExportQueryExecutionTrees {
static std::optional<std::pair<std::string, const char*>>
idToStringAndTypeForEncodedValue(Id id);

// Same as the 'idToStringAndType' above but returning a LiteralOrIri instead
// of a std::pair<std::string, const char*>
static std::optional<LiteralOrIri> idToLiteralOrIri(
const Index& index, Id id, const LocalVocab& localVocab);
// Same as the previous function, but only handles the datatypes for which the
// value is encoded directly in the ID. For other datatypes an exception is
// thrown.
static std::optional<LiteralOrIri> idToLiteralOrIriForEncodedValue(Id id);

// Acts as a helper to retrieve an LiteralOrIri object
// from an Id, where the Id is of type `VocabIndex` or `LocalVocabIndex`.
// This function should only be called with suitable `Datatype` Id's,
Expand Down
13 changes: 13 additions & 0 deletions src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ std::optional<std::string> StringValueGetter::operator()(
}
}

// ____________________________________________________________________________
std::optional<LiteralOrIri> LiteralOrIriValueGetter::operator()(
Id id, const EvaluationContext* context) const {
auto optionalLiteralOrIriAndType =
ExportQueryExecutionTrees::idToLiteralOrIri(context->_qec.getIndex(), id,
context->_localVocab);
if (optionalLiteralOrIriAndType.has_value()) {
return std::move(optionalLiteralOrIriAndType.value());
} else {
return std::nullopt;
}
}

// ____________________________________________________________________________
template <auto isSomethingFunction, auto prefix>
Id IsSomethingValueGetter<isSomethingFunction, prefix>::operator()(
Expand Down
14 changes: 14 additions & 0 deletions src/engine/sparqlExpressions/SparqlExpressionValueGetters.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ struct StringValueGetter : Mixin<StringValueGetter> {
}
};

// This class can be used as the `ValueGetter` argument of Expression
// templates. It produces a LiteralOrIri.
struct LiteralOrIriValueGetter : Mixin<LiteralOrIriValueGetter> {
using Mixin<LiteralOrIriValueGetter>::operator();

std::optional<LiteralOrIri> operator()(ValueId,
const EvaluationContext*) const;

std::optional<LiteralOrIri> operator()(const LiteralOrIri& s,
const EvaluationContext*) const {
return s;
}
};

// Value getter for `isBlank`.
struct IsBlankNodeValueGetter : Mixin<IsBlankNodeValueGetter> {
using Mixin<IsBlankNodeValueGetter>::operator();
Expand Down
2 changes: 2 additions & 0 deletions src/engine/sparqlExpressions/StringExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ class SubstrImpl {
};

public:
// TODO<DuDaAG> Statt s vom Typ std::optional<std::string>, s vom Typ
// std::optional<LiteralOrIri>
IdOrLiteralOrIri operator()(std::optional<std::string> s, NumericValue start,
NumericValue length) const {
if (!s.has_value() || std::holds_alternative<NotNumeric>(start) ||
Expand Down
4 changes: 2 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ endfunction()
# required e.g. if several tests cases write to the same file.
function(linkAndDiscoverTestSerial basename)
linkTest(${basename} ${ARGN})
gtest_discover_tests(${basename} ${basename} PROPERTIES RUN_SERIAL
gtest_discover_tests(${basename} ${basename} DISCOVERY_TIMEOUT 600 PROPERTIES RUN_SERIAL
TRUE)
endfunction()

if (SINGLE_TEST_BINARY)
message(STATUS "All tests are linked into a single executable `QLeverAllUnitTestsMain`")
add_executable(QLeverAllUnitTestsMain)
qlever_target_link_libraries(QLeverAllUnitTestsMain gtest gmock_main testUtil ${CMAKE_THREAD_LIBS_INIT})
gtest_discover_tests(QLeverAllUnitTestsMain QLeverAllUnitTestsMain PROPERTIES RUN_SERIAL
gtest_discover_tests(QLeverAllUnitTestsMain QLeverAllUnitTestsMain DISCOVERY_TIMEOUT 600 PROPERTIES RUN_SERIAL
TRUE)
else ()
message(STATUS "The tests are split over multiple binaries")
Expand Down
58 changes: 58 additions & 0 deletions test/ExportQueryExecutionTreesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1482,3 +1482,61 @@ TEST(ExportQueryExecutionTrees, convertGeneratorForChunkedTransfer) {
AllOf(HasSubstr("!!!!>># An error has occurred"),
HasSubstr("A very strange")));
}

TEST(ExportQueryExecutionTrees, idToLiteralOrIriFunctionality1) {
std::string kg = "<s> <p> 31 . <s> <o> 42";
auto qec = ad_utility::testing::getQec(kg);
auto getId = ad_utility::testing::makeGetId(qec->getIndex());
using enum Datatype;

// Case VocabIndex
{
Id id = getId("<o>");
ASSERT_EQ(id.getDatatype(), VocabIndex);
auto resultLiteral = ExportQueryExecutionTrees::idToLiteralOrIri(
qec->getIndex(), id, LocalVocab{});
EXPECT_EQ(resultLiteral.value().toStringRepresentation(), "<o>");
}

// Case Int
{
Id id = ad_utility::testing::IntId(1);
auto resultLiteral = ExportQueryExecutionTrees::idToLiteralOrIri(
qec->getIndex(), id, LocalVocab{});
EXPECT_EQ(resultLiteral.value().toStringRepresentation(),
"\"1\"^^<http://www.w3.org/2001/XMLSchema#int>");
}

// Case Double
{
Id id = ad_utility::testing::DoubleId(1.2);
auto resultLiteral = ExportQueryExecutionTrees::idToLiteralOrIri(
qec->getIndex(), id, LocalVocab{});
EXPECT_EQ(resultLiteral.value().toStringRepresentation(),
"\"1.2\"^^<http://www.w3.org/2001/XMLSchema#double>");
}
{
// Case Bool
Id id = ad_utility::testing::BoolId(true);
auto resultLiteral = ExportQueryExecutionTrees::idToLiteralOrIri(
qec->getIndex(), id, LocalVocab{});
EXPECT_EQ(resultLiteral.value().toStringRepresentation(),
"\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>");
}
{
// Case Date
Id id = ad_utility::testing::DateId(DateYearOrDuration::parseXsdDate,
"2024-11-07");
auto resultLiteral = ExportQueryExecutionTrees::idToLiteralOrIri(
qec->getIndex(), id, LocalVocab{});
EXPECT_EQ(resultLiteral.value().toStringRepresentation(),
"\"2024-11-07\"^^<http://www.w3.org/2001/XMLSchema#date>");
}
// Case Undefined
{
Id id = ad_utility::testing::UndefId();
auto resultLiteral = ExportQueryExecutionTrees::idToLiteralOrIri(
qec->getIndex(), id, LocalVocab{});
EXPECT_EQ(resultLiteral, std::nullopt);
}
}

0 comments on commit 0ed79df

Please sign in to comment.