Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add timezone conversion. #37

Merged
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ install(DIRECTORY ${nebula_common_source_dir}/src/common/graph
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/common
FILES_MATCHING PATTERN "*.h")

# reuse the time utils in common
install(DIRECTORY ${nebula_common_source_dir}/src/common/time
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/common
FILES_MATCHING PATTERN "TimeConversion.h")

# reuse the thrift types in common
install(
FILES
Expand Down
34 changes: 31 additions & 3 deletions include/nebula/client/Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#pragma once

#include <common/datatypes/DataSet.h>

#include "nebula/client/Connection.h"

namespace nebula {
Expand All @@ -22,20 +24,27 @@ class Session {
Connection &&conn,
ConnectionPool *pool,
const std::string &username,
const std::string &password)
const std::string &password,
const std::string &timezoneName,
int32_t offsetSecs)
: sessionId_(sessionId),
conn_(std::move(conn)),
pool_(pool),
username_(username),
password_(password) {}
password_(password),
timezoneName_(timezoneName),
offsetSecs_(offsetSecs) {}
Session(Session &&session)
: sessionId_(session.sessionId_),
conn_(std::move(session.conn_)),
pool_(session.pool_),
username_(std::move(session.username_)),
password_(std::move(session.password_)) {
password_(std::move(session.password_)),
timezoneName_(std::move(session.timezoneName_)),
offsetSecs_(session.offsetSecs_) {
session.sessionId_ = -1;
session.pool_ = nullptr;
session.offsetSecs_ = 0;
}
~Session() {
release();
Expand All @@ -59,12 +68,31 @@ class Session {
return sessionId_ > 0;
}

const std::string& timeZoneName() const {
return timezoneName_;
}

int32_t timeZoneOffsetSecs() const {
return offsetSecs_;
}

// convert the time to server time zone
void toLocal(DataSet &data) {
return toLocal(data, offsetSecs_);
}

// convert the time to specific time zone
static void toLocal(DataSet &data, int32_t offsetSecs);

private:
int64_t sessionId_{-1};
Connection conn_;
ConnectionPool *pool_{nullptr};
std::string username_;
std::string password_;
// empty means not a named timezone
std::string timezoneName_;
int32_t offsetSecs_;
};

} // namespace nebula
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(NEBULA_CLIENT_OBJS
$<TARGET_OBJECTS:common_graph_thrift_obj>
$<TARGET_OBJECTS:common_datatypes_obj>
$<TARGET_OBJECTS:common_graph_obj>
$<TARGET_OBJECTS:common_time_utils_obj>
)

set(NEBULA_CLIENT_SOURCES
Expand Down
3 changes: 2 additions & 1 deletion src/client/ConnectionPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ Session ConnectionPool::getSession(const std::string &username,
if (resp.errorCode != ErrorCode::SUCCEEDED || resp.sessionId == nullptr) {
return Session();
}
return Session(*resp.sessionId, std::move(conn), this, username, password);
return Session(*resp.sessionId, std::move(conn), this, username, password,
*resp.timeZoneName, *resp.timeZoneOffsetSeconds);
}

Connection ConnectionPool::getConnection() {
Expand Down
14 changes: 14 additions & 0 deletions src/client/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* attached with Common Clause Condition 1.0, found in the LICENSES directory.
*/

#include <common/time/TimeConversion.h>

#include "nebula/client/Session.h"
#include "nebula/client/ConnectionPool.h"

Expand Down Expand Up @@ -48,4 +50,16 @@ void Session::release() {
}
}

void Session::toLocal(DataSet &data, int32_t offsetSecs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to provide a method like that, but you can tell user how to get localTime and get localDateTime in example code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface better move to test code, no need to provide it to the user

Copy link
Contributor Author

@Shylock-Hg Shylock-Hg Jun 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User could use or not.

for (auto &row : data.rows) {
for (auto &col : row.values) {
if (col.isTime()) {
col.setTime(time::TimeConversion::timeShift(col.getTime(), offsetSecs));
} else if (col.isDateTime()) {
col.setDateTime(time::TimeConversion::dateTimeShift(col.getDateTime(), offsetSecs));
}
}
}
}

} // namespace nebula
13 changes: 13 additions & 0 deletions src/client/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,16 @@ nebula_add_test(
gtest
${NEBULA_CLIENT_LIBRARIES}
)

nebula_add_test(
NAME
timezone_conversion_test
SOURCES
TimezoneConversionTest.cpp
OBJECTS
${NEBULA_CLIENT_OBJS}
$<TARGET_OBJECTS:nebula_graph_client_obj>
LIBRARIES
gtest
${NEBULA_CLIENT_LIBRARIES}
)
21 changes: 20 additions & 1 deletion src/client/tests/ClientTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#pragma once

#include <gtest/gtest.h>
class ClientTest : public ::testing::Test {
protected:
static ::testing::AssertionResult verifyResultWithoutOrder(const nebula::DataSet& resp,
Expand All @@ -20,5 +21,23 @@ class ClientTest : public ::testing::Test {
}
return ::testing::AssertionSuccess();
}
};

static ::testing::AssertionResult verifyResultWithoutOrder(
const nebula::ExecutionResponse& resp,
const nebula::DataSet& expect) {
auto result = succeeded(resp);
if (!result) {
return result;
}
const auto& data = *resp.data;
return verifyResultWithoutOrder(data, expect);
}

static ::testing::AssertionResult succeeded(const nebula::ExecutionResponse& resp) {
if (resp.errorCode != nebula::ErrorCode::SUCCEEDED) {
return ::testing::AssertionFailure()
<< "Execution Failed with error: " << resp.errorCode << "," << *resp.errorMsg;
}
return ::testing::AssertionSuccess();
}
};
73 changes: 73 additions & 0 deletions src/client/tests/TimezoneConversionTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Copyright (c) 2021 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License,
* attached with Common Clause Condition 1.0, found in the LICENSES directory.
*/

#include <atomic>
#include <chrono>
#include <thread>

#include <folly/synchronization/Baton.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <gtest/gtest_prod.h>

#include <nebula/client/ConnectionPool.h>
#include <nebula/client/Init.h>
#include <nebula/client/Session.h>

#include "./ClientTest.h"

// Require a nebula server could access

#define kServerHost "graphd"

class SessionTest : public ClientTest {};

TEST_F(SessionTest, Basic) {
nebula::ConnectionPool pool;
pool.init({kServerHost ":9669"}, nebula::Config{});
auto session = pool.getSession("root", "nebula");
ASSERT_TRUE(session.valid());
{
auto resp = session.execute("YIELD datetime(\"2019-03-22T22:04:30\") as dt,"
"date(\"2019-03-22\") as d, "
"time(\"22:04:30\") as t");
nebula::DataSet data({"dt", "d", "t"});
data.emplace_back(nebula::Row({nebula::DateTime(2019, 3, 22, 22, 4, 30, 0),
nebula::Date(2019, 3, 22),
nebula::Time(22, 4, 30, 0)}));
EXPECT_TRUE(verifyResultWithoutOrder(resp, data));

// conversion
session.toLocal(*resp.data);
EXPECT_TRUE(verifyResultWithoutOrder(*resp.data, data));
}
{
auto resp = session.execute("YIELD datetime(\"2019-03-22T22:04:30\") as dt,"
"date(\"2019-03-22\") as d, "
"time(\"22:04:30\") as t");
nebula::DataSet data({"dt", "d", "t"});
data.emplace_back(nebula::Row({nebula::DateTime(2019, 3, 22, 22, 4, 30, 0),
nebula::Date(2019, 3, 22),
nebula::Time(22, 4, 30, 0)}));
EXPECT_TRUE(verifyResultWithoutOrder(resp, data));

// conversion
session.toLocal(*resp.data, 30);
nebula::DataSet expectLocal({"dt", "d", "t"});
expectLocal.emplace_back(nebula::Row({nebula::DateTime(2019, 3, 22, 22, 5, 0, 0),
nebula::Date(2019, 3, 22),
nebula::Time(22, 5, 0, 0)}));
EXPECT_TRUE(verifyResultWithoutOrder(*resp.data, expectLocal));
}
}

int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
nebula::init(&argc, &argv);
google::SetStderrLogging(google::INFO);

return RUN_ALL_TESTS();
}