Skip to content

Commit

Permalink
Implemented function NOW() (#1377)
Browse files Browse the repository at this point in the history
* Added conversion str to int

* templated function for toNumeric, add declaration to NaryExpression.h

* str to num for SparqlExpression implemented + added test

* Update src/engine/sparqlExpressions/StringExpressions.cpp

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>

* Update src/engine/sparqlExpressions/StringExpressions.cpp

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>

* Update src/engine/sparqlExpressions/StringExpressions.cpp

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>

* Update src/engine/sparqlExpressions/StringExpressions.cpp

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>

* using now absl::from_chars() and stripping whitespaces for string to number conv.

* added new functions to processIriFuntionCall() (for string to number)

* renaming to: toIntExpression and toDoubleExpression for later more general implementation

* made format (clang-format-16)

* Update src/parser/sparqlParser/SparqlQleverVisitor.cpp

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>

* Update src/parser/sparqlParser/SparqlQleverVisitor.cpp

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>

* renaming in NaryExpression.h for accordance with other function, adding correct prefix in Constants.h

* added test coverage for function calls makeIntExpression and make DoubleExpression

* toNumeric has now correct behavior and uses absl::from_chars() and std::from_chars()

* made clang-format for NaryExpressionImpl.h

* first implementation NOW() expression

* fix spelling error

* pass by reference

* changes w.r.t. pull-request comments

* last changes for #1377

---------

Co-authored-by: Johannes Kalmbach <joka921@users.noreply.github.com>
  • Loading branch information
realHannes and joka921 committed Jun 19, 2024
1 parent f9e730c commit 1be8381
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 16 deletions.
38 changes: 38 additions & 0 deletions src/engine/sparqlExpressions/NowDatetimeExpression.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures
// Author: Hannes Baumann <baumannh@informatik.uni-freiburg.de>

#include "engine/sparqlExpressions/SparqlExpression.h"
#include "util/ChunkedForLoop.h"
#include "util/Date.h"
#include "util/Random.h"

namespace sparqlExpression {

// The expression `NOW()` is evaluated within NowDatetimeExpression.h.
// `NowDatetimeExpression` has to be explicitly constructed from a
// `date-formatted string`, which is for all evaluations within a Sparql
// query the same.
class NowDatetimeExpression : public SparqlExpression {
private:
DateOrLargeYear date_;

public:
explicit NowDatetimeExpression(const std::string& dateTimeFormat)
: date_(DateOrLargeYear::parseXsdDatetime(dateTimeFormat)) {}

std::string getCacheKey(
[[maybe_unused]] const VariableToColumnMap& varColMap) const override {
return absl::StrCat("NOW ", date_.toBits());
}

ExpressionResult evaluate(
[[maybe_unused]] EvaluationContext* context) const override {
return Id::makeFromDate(date_);
}

private:
std::span<SparqlExpression::Ptr> childrenImpl() override { return {}; }
};

} // namespace sparqlExpression
15 changes: 14 additions & 1 deletion src/parser/sparqlParser/SparqlQleverVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@
#include <string>
#include <vector>

#include "absl/time/time.h"
#include "engine/sparqlExpressions/GroupConcatExpression.h"
#include "engine/sparqlExpressions/LangExpression.h"
#include "engine/sparqlExpressions/LiteralExpression.h"
#include "engine/sparqlExpressions/NowDatetimeExpression.h"
#include "engine/sparqlExpressions/RandomExpression.h"
#include "engine/sparqlExpressions/RegexExpression.h"
#include "engine/sparqlExpressions/RelationalExpressions.h"
#include "engine/sparqlExpressions/SampleExpression.h"
#include "engine/sparqlExpressions/UuidExpressions.h"
#include "parser/SparqlParser.h"
#include "parser/TokenizerCtre.h"
#include "parser/TurtleParser.h"
#include "parser/data/Variable.h"
#include "util/OnDestructionDontThrowDuringStackUnwinding.h"
#include "util/StringUtils.h"
#include "util/TransparentFunctors.h"
#include "util/antlr/GenerateAntlrExceptionMetadata.h"
Expand Down Expand Up @@ -55,6 +59,12 @@ std::string Visitor::getOriginalInputForContext(
ad_utility::getUTF8Substring(fullInput, posBeg, posEnd - posBeg + 1)};
}

// _____________________________________________________________________________
std::string Visitor::currentTimeAsXsdString() {
return absl::FormatTime("%Y-%m-%dT%H:%M:%E3S%Ez", absl::Now(),
absl::LocalTimeZone());
}

// ___________________________________________________________________________
ExpressionPtr Visitor::processIriFunctionCall(
const TripleComponent::Iri& iri, std::vector<ExpressionPtr> argList,
Expand Down Expand Up @@ -2001,6 +2011,9 @@ ExpressionPtr Visitor::visit([[maybe_unused]] Parser::BuiltInCallContext* ctx) {
return createUnary(&makeDayExpression);
} else if (functionName == "tz") {
return createUnary(&makeTimezoneStrExpression);
} else if (functionName == "now") {
AD_CONTRACT_CHECK(argList.empty());
return std::make_unique<NowDatetimeExpression>(startTime_);
} else if (functionName == "hours") {
return createUnary(&makeHoursExpression);
} else if (functionName == "minutes") {
Expand Down
23 changes: 8 additions & 15 deletions src/parser/sparqlParser/SparqlQleverVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,11 @@
#include <antlr4-runtime.h>

#include "engine/sparqlExpressions/AggregateExpression.h"
#include "engine/sparqlExpressions/GroupConcatExpression.h"
#include "engine/sparqlExpressions/LiteralExpression.h"
#include "engine/sparqlExpressions/NaryExpression.h"
#include "engine/sparqlExpressions/SampleExpression.h"
#include "engine/sparqlExpressions/SparqlExpressionPimpl.h"
#include "parser/Alias.h"
#include "parser/ConstructClause.h"
#include "parser/ParsedQuery.h"
#include "parser/RdfEscaping.h"
#include "parser/data/BlankNode.h"
#include "parser/data/GraphRef.h"
#include "parser/data/Iri.h"
#include "parser/data/SolutionModifiers.h"
#include "parser/data/Types.h"
#undef EOF
#include "parser/sparqlParser/generated/SparqlAutomaticVisitor.h"
#define EOF std::char_traits<char>::eof()
#include "util/HashMap.h"
#include "util/OverloadCallOperator.h"
#include "util/StringUtils.h"

template <typename T>
class Reversed {
Expand Down Expand Up @@ -472,6 +457,14 @@ class SparqlQleverVisitor {
string visit(Parser::PnameNsContext* ctx);

private:
// Helper to assign variable `startTime_` a correctly formatted time string.
static std::string currentTimeAsXsdString();

// Member starTime_ is needed for the NOW expression. All calls within
// the query execution reference it. The underlying date time format is e.g.:
// 2011-01-10T14:45:13.815-05:00
std::string startTime_ = currentTimeAsXsdString();

template <typename Visitor, typename Ctx>
static constexpr bool voidWhenVisited =
std::is_void_v<decltype(std::declval<Visitor&>().visit(
Expand Down
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ addLinkAndDiscoverTest(ExceptionTest)

addLinkAndDiscoverTestSerial(RandomExpressionTest index)

addLinkAndDiscoverTestSerial(NowDatetimeExpressionTest index)

addLinkAndDiscoverTestSerial(SortTest engine)

addLinkAndDiscoverTestSerial(OrderByTest engine)
Expand Down
57 changes: 57 additions & 0 deletions test/NowDatetimeExpressionTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures
// Author: Hannes Baumann <baumannh@informatik.uni-freiburg.de>

#include "./SparqlExpressionTestHelpers.h"
#include "engine/sparqlExpressions/NowDatetimeExpression.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

using namespace sparqlExpression;

TEST(NowDatetimeExpression, nowExpressionEvaluate) {
std::string strDate = "2011-01-10T14:45:13.815-05:00";
TestContext testContext{};
auto& evaluationContext = testContext.context;

// technically the evaluation context isn't necessary.
evaluationContext._beginIndex = 43;
evaluationContext._endIndex = 1044;

// The result should hold an ID (from Date) given that NOW() should return by
// definition a xsd:dateTime: "2011-01-10T14:45:13.815-05:00"^^xsd:dateTime
auto resultAsVariant =
NowDatetimeExpression{strDate}.evaluate(&evaluationContext);
ASSERT_TRUE(std::holds_alternative<Id>(resultAsVariant));
const auto& resultDate = std::get<Id>(resultAsVariant);

DateOrLargeYear dateNowTest =
DateOrLargeYear(DateOrLargeYear::parseXsdDatetime(strDate));

ASSERT_EQ(resultDate.getDatatype(), Datatype::Date);
ASSERT_EQ(resultDate.getDate(), dateNowTest);

evaluationContext._isPartOfGroupBy = true;
auto resultAsVariant2 =
NowDatetimeExpression{strDate}.evaluate(&evaluationContext);
ASSERT_TRUE(std::holds_alternative<Id>(resultAsVariant2));
DateOrLargeYear singleDateNow = std::get<Id>(resultAsVariant2).getDate();
ASSERT_EQ(singleDateNow, dateNowTest);
}

TEST(NowDatetimeExpression, getCacheKeyNowExpression) {
std::string strDate1 = "2011-01-10T14:45:13.815-05:00";
std::string strDate2 = "2024-06-18T12:16:33.815-06:00";
NowDatetimeExpression dateNow1(strDate1);
NowDatetimeExpression dateNow2(strDate2);
ASSERT_TRUE(dateNow1.getUnaggregatedVariables().empty());
auto cacheKey1 = dateNow1.getCacheKey({});
ASSERT_THAT(cacheKey1, ::testing::StartsWith("NOW "));
ASSERT_EQ(cacheKey1, dateNow1.getCacheKey({}));
// Given that these use the same date-time string the key should be equal.
ASSERT_EQ(cacheKey1, NowDatetimeExpression{strDate1}.getCacheKey({}));
// Given that dateNow1 and dateNow2 are constructed from different date-time
// strings, it should be rather unlikely that their cache-keys are equal.
auto cacheKey2 = dateNow2.getCacheKey({});
ASSERT_NE(cacheKey1, cacheKey2);
}
2 changes: 2 additions & 0 deletions test/SparqlAntlrParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "SparqlAntlrParserTestHelpers.h"
#include "engine/sparqlExpressions/LangExpression.h"
#include "engine/sparqlExpressions/LiteralExpression.h"
#include "engine/sparqlExpressions/NowDatetimeExpression.h"
#include "engine/sparqlExpressions/RandomExpression.h"
#include "engine/sparqlExpressions/RegexExpression.h"
#include "engine/sparqlExpressions/UuidExpressions.h"
Expand Down Expand Up @@ -1385,6 +1386,7 @@ TEST(SparqlParser, builtInCall) {
expectBuiltInCall("month(?x)", matchUnary(&makeMonthExpression));
expectBuiltInCall("tz(?x)", matchUnary(&makeTimezoneStrExpression));
expectBuiltInCall("day(?x)", matchUnary(&makeDayExpression));
expectBuiltInCall("NOW()", matchPtr<NowDatetimeExpression>());
expectBuiltInCall("hours(?x)", matchUnary(&makeHoursExpression));
expectBuiltInCall("minutes(?x)", matchUnary(&makeMinutesExpression));
expectBuiltInCall("seconds(?x)", matchUnary(&makeSecondsExpression));
Expand Down

0 comments on commit 1be8381

Please sign in to comment.