diff --git a/src/executor/CMakeLists.txt b/src/executor/CMakeLists.txt index 9aa9e3ebfc6c1a25aaac977e7a80614e076b9028..227104dc12b464b8e757e010716125d599465854 100644 --- a/src/executor/CMakeLists.txt +++ b/src/executor/CMakeLists.txt @@ -45,6 +45,7 @@ add_library( SetExecutor.cpp FindExecutor.cpp MatchExecutor.cpp + DeleteVertexExecutor.cpp ) add_dependencies( graph_obj diff --git a/src/executor/DeleteVertexExecutor.cpp b/src/executor/DeleteVertexExecutor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f778d0143d6b50f59b216dbbafff8d805bfa7749 --- /dev/null +++ b/src/executor/DeleteVertexExecutor.cpp @@ -0,0 +1,113 @@ +/* Copyright (c) 2019 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 "graph/DeleteVertexExecutor.h" +#include "storage/client/StorageClient.h" + +namespace nebula { +namespace graph { + +DeleteVertexExecutor::DeleteVertexExecutor(Sentence *sentence, + ExecutionContext *ectx) : Executor(ectx) { + sentence_ = static_cast<DeleteVertexSentence*>(sentence); +} + +Status DeleteVertexExecutor::prepare() { + auto ovalue = sentence_->vid()->eval(); + auto v = ovalue.value(); + if (!Expression::isInt(v)) { + return Status::Error("Vertex ID should be of type integer"); + } + vid_ = Expression::asInt(v); + return Status::OK(); +} + +void DeleteVertexExecutor::execute() { + GraphSpaceID space = ectx()->rctx()->session()->space(); + // TODO(zlcook) Get edgeKes of a vertex by Go + auto future = ectx()->storage()->getEdgeKeys(space, vid_); + auto *runner = ectx()->rctx()->runner(); + auto cb = [this] (auto &&resp) { + if (!resp.ok()) { + DCHECK(onError_); + onError_(Status::Error("Internal Error")); + return; + } + auto rpcResp = std::move(resp).value(); + std::vector<storage::cpp2::EdgeKey> allEdges; + for (auto& edge : *rpcResp.get_edge_keys()) { + auto reverseEdge = storage::cpp2::EdgeKey(apache::thrift::FragileConstructor::FRAGILE, + edge.get_dst(), + -(edge.get_edge_type()), + edge.get_ranking(), + edge.get_src()); + allEdges.emplace_back(std::move(edge)); + allEdges.emplace_back(std::move(reverseEdge)); + } + deleteEdges(&allEdges); + return; + }; + + auto error = [this] (auto &&e) { + LOG(ERROR) << "Exception caught: " << e.what(); + DCHECK(onError_); + onError_(Status::Error("Internal error")); + return; + }; + std::move(future).via(runner).thenValue(cb).thenError(error); +} + +void DeleteVertexExecutor::deleteEdges(std::vector<storage::cpp2::EdgeKey>* edges) { + GraphSpaceID space = ectx()->rctx()->session()->space(); + auto future = ectx()->storage()->deleteEdges(space, *edges); + auto *runner = ectx()->rctx()->runner(); + auto cb = [this] (auto &&resp) { + auto completeness = resp.completeness(); + if (completeness != 100) { + DCHECK(onError_); + onError_(Status::Error("Internal Error")); + return; + } + deleteVertex(); + return; + }; + + auto error = [this] (auto &&e) { + LOG(ERROR) << "Exception caught: " << e.what(); + DCHECK(onError_); + onError_(Status::Error("Internal error")); + return; + }; + std::move(future).via(runner).thenValue(cb).thenError(error); +} + +void DeleteVertexExecutor::deleteVertex() { + GraphSpaceID space = ectx()->rctx()->session()->space(); + auto future = ectx()->storage()->deleteVertex(space, vid_); + auto *runner = ectx()->rctx()->runner(); + auto cb = [this] (auto &&resp) { + if (!resp.ok()) { + DCHECK(onError_); + onError_(Status::Error("Internal Error")); + return; + } + DCHECK(onFinish_); + onFinish_(); + return; + }; + + auto error = [this] (auto &&e) { + LOG(ERROR) << "Exception caught: " << e.what(); + DCHECK(onError_); + onError_(Status::Error("Internal error")); + return; + }; + std::move(future).via(runner).thenValue(cb).thenError(error); +} + +} // namespace graph +} // namespace nebula + diff --git a/src/executor/DeleteVertexExecutor.h b/src/executor/DeleteVertexExecutor.h new file mode 100644 index 0000000000000000000000000000000000000000..7a2cc2d02b6a4f877d545244f3066e80111c1ebc --- /dev/null +++ b/src/executor/DeleteVertexExecutor.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2019 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. + */ + +#ifndef GRAPH_DELETEVERTEXEXECUTOR_H_ +#define GRAPH_DELETEVERTEXEEXECUTOR_H_ + +#include "base/Base.h" +#include "graph/Executor.h" + +namespace nebula { +namespace graph { + +class DeleteVertexExecutor final : public Executor { +public: + DeleteVertexExecutor(Sentence *sentence, ExecutionContext *ectx); + + const char* name() const override { + return "DeleteVertexExecutor"; + } + + Status MUST_USE_RESULT prepare() override; + + void execute() override; + +private: + void deleteEdges(std::vector<storage::cpp2::EdgeKey>* edges); + void deleteVertex(); + +private: + DeleteVertexSentence *sentence_{nullptr}; + VertexID vid_; +}; + +} // namespace graph +} // namespace nebula + +#endif // GRAPH_DELETEVERTEXEXECUTOR_H_ diff --git a/src/executor/Executor.cpp b/src/executor/Executor.cpp index 65b0c26ce056704d2a88e3cc6ce8ad5ed61ee322..3fc6105d2e73b4ec43f76867694fe692bca5a0d7 100644 --- a/src/executor/Executor.cpp +++ b/src/executor/Executor.cpp @@ -42,6 +42,7 @@ #include "graph/FindExecutor.h" #include "graph/MatchExecutor.h" #include "graph/BalanceExecutor.h" +#include "graph/DeleteVertexExecutor.h" namespace nebula { namespace graph { @@ -143,6 +144,9 @@ std::unique_ptr<Executor> Executor::makeExecutor(Sentence *sentence) { case Sentence::Kind::kBalance: executor = std::make_unique<BalanceExecutor>(sentence, ectx()); break; + case Sentence::Kind::kDeleteVertex: + executor = std::make_unique<DeleteVertexExecutor>(sentence, ectx()); + break; case Sentence::Kind::kUnknown: LOG(FATAL) << "Sentence kind unknown"; break; diff --git a/src/executor/test/CMakeLists.txt b/src/executor/test/CMakeLists.txt index d8e70e7e06be4c28bdceb4851226cc83fd4a60d9..b24316e36d6a8cf5f1813390f1579eadb3767131 100644 --- a/src/executor/test/CMakeLists.txt +++ b/src/executor/test/CMakeLists.txt @@ -204,3 +204,21 @@ nebula_add_test( wangle gtest ) + +nebula_add_test( + NAME + deleteVertex_test + SOURCES + DeleteVertexTest.cpp + OBJECTS + $<TARGET_OBJECTS:graph_test_common_obj> + $<TARGET_OBJECTS:client_cpp_obj> + $<TARGET_OBJECTS:adHocSchema_obj> + $<TARGET_OBJECTS:http_client_obj> + ${GRAPH_TEST_LIBS} + LIBRARIES + ${THRIFT_LIBRARIES} + ${ROCKSDB_LIBRARIES} + wangle + gtest +) diff --git a/src/executor/test/DeleteVertexTest.cpp b/src/executor/test/DeleteVertexTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9a5f81f6ea5cc88515a300ceeafb488dfd57f61 --- /dev/null +++ b/src/executor/test/DeleteVertexTest.cpp @@ -0,0 +1,118 @@ +/* Copyright (c) 2019 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 "base/Base.h" +#include "graph/test/TestEnv.h" +#include "graph/test/TestBase.h" +#include "graph/test/TraverseTestBase.h" +#include "meta/test/TestUtils.h" + + +namespace nebula { +namespace graph { + +class DeleteVertexTest : public TraverseTestBase { + protected: + void SetUp() override { + TraverseTestBase::SetUp(); + } + + void TearDown() override { + TraverseTestBase::TearDown(); + } +}; + +TEST_F(DeleteVertexTest, base) { + // Check + { + cpp2::ExecutionResponse resp; + auto *fmt = "GO FROM %ld OVER like"; + auto query = folly::stringPrintf(fmt, players_["Boris Diaw"].vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector<std::tuple<int64_t>> expected = { + {players_["Tony Parker"].vid()}, + {players_["Tim Duncan"].vid()}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + cpp2::ExecutionResponse resp; + auto &player = players_["Tony Parker"]; + auto *fmt = "FETCH PROP ON player %ld YIELD player.name, player.age"; + auto query = folly::stringPrintf(fmt, player.vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector<std::tuple<std::string, int64_t>> expected = { + {player.name(), player.age()}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + cpp2::ExecutionResponse resp; + auto &player = players_["Tony Parker"]; + auto &serve = player.serves()[0]; + auto &team = teams_[std::get<0>(serve)]; + auto *fmt = "FETCH PROP ON serve %ld->%ld" + " YIELD serve.start_year, serve.end_year"; + auto query = folly::stringPrintf(fmt, player.vid(), team.vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector<std::tuple<int64_t, int64_t>> expected = { + {std::get<1>(serve), std::get<2>(serve)}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + // Delete vertex + { + cpp2::ExecutionResponse resp; + auto *fmt = "DELETE VERTEX %ld"; + auto query = folly::stringPrintf(fmt, players_["Tony Parker"].vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + } + // Check again + { + cpp2::ExecutionResponse resp; + auto *fmt = "GO FROM %ld OVER like"; + auto query = folly::stringPrintf(fmt, players_["Boris Diaw"].vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector<std::tuple<int64_t>> expected = { + {players_["Tim Duncan"].vid()}, + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + cpp2::ExecutionResponse resp; + auto &player = players_["Tony Parker"]; + auto *fmt = "FETCH PROP ON player %ld YIELD player.name, player.age"; + auto query = folly::stringPrintf(fmt, player.vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector<std::tuple<std::string, int64_t>> expected = { + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } + { + cpp2::ExecutionResponse resp; + auto &player = players_["Tony Parker"]; + auto &serve = player.serves()[0]; + auto &team = teams_[std::get<0>(serve)]; + auto *fmt = "FETCH PROP ON serve %ld->%ld" + " YIELD serve.start_year, serve.end_year"; + auto query = folly::stringPrintf(fmt, player.vid(), team.vid()); + auto code = client_->execute(query, resp); + ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code); + std::vector<std::tuple<int64_t, int64_t>> expected = { + }; + ASSERT_TRUE(verifyResult(resp, expected)); + } +} + +} // namespace graph +} // namespace nebula + diff --git a/src/parser/MutateSentences.cpp b/src/parser/MutateSentences.cpp index cd6c44bc7c990f8f6ffd988a952c7abb533b0f07..8a091fa32e38b2f48f7ee56a2069d220f2b76884 100644 --- a/src/parser/MutateSentences.cpp +++ b/src/parser/MutateSentences.cpp @@ -230,11 +230,7 @@ std::string DeleteVertexSentence::toString() const { std::string buf; buf.reserve(256); buf += "DELETE VERTEX "; - buf += vidList_->toString(); - if (whereClause_ != nullptr) { - buf += " "; - buf += whereClause_->toString(); - } + buf += vid_->toString(); return buf; } diff --git a/src/parser/MutateSentences.h b/src/parser/MutateSentences.h index 0e75912687e6b4b1c8104a74ca065d3d4827df75..02bdea43425c199a37b5070acb891d935b453b6c 100644 --- a/src/parser/MutateSentences.h +++ b/src/parser/MutateSentences.h @@ -405,28 +405,19 @@ private: class DeleteVertexSentence final : public Sentence { public: - explicit DeleteVertexSentence(VertexIDList *vidList) { - vidList_.reset(vidList); + explicit DeleteVertexSentence(Expression *vid) { + vid_.reset(vid); kind_ = Kind::kDeleteVertex; } - auto vidList() const { - return vidList_->vidList(); - } - - void setWhereClause(WhereClause *clause) { - whereClause_.reset(clause); - } - - const WhereClause* whereClause() const { - return whereClause_.get(); + Expression* vid() const { + return vid_.get(); } std::string toString() const override; private: - std::unique_ptr<VertexIDList> vidList_; - std::unique_ptr<WhereClause> whereClause_; + std::unique_ptr<Expression> vid_; }; diff --git a/src/parser/parser.yy b/src/parser/parser.yy index e5fb90dacaba4f857199360d13bed6848bd05307..9f7ad2b18f68bd3ce991e97a97986784216404d9 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -1155,9 +1155,8 @@ update_edge_sentence ; delete_vertex_sentence - : KW_DELETE KW_VERTEX vid_list where_clause { + : KW_DELETE KW_VERTEX vid { auto sentence = new DeleteVertexSentence($3); - sentence->setWhereClause($4); $$ = sentence; } ; diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index efbf5f6a00653b414ab3fe43cb4214f250b5d30f..8caa03e9f2c2faf20d644714fcc167331096d8ed 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -662,19 +662,7 @@ TEST(Parser, DeleteVertex) { } { GQLParser parser; - std::string query = "DELETE VERTEX 123,456,789"; - auto result = parser.parse(query); - ASSERT_TRUE(result.ok()) << result.status(); - } - { - GQLParser parser; - std::string query = "DELETE VERTEX 12345 WHERE salary > 10000"; - auto result = parser.parse(query); - ASSERT_TRUE(result.ok()) << result.status(); - } - { - GQLParser parser; - std::string query = "DELETE VERTEX 123,456,789 WHERE salary > 10000"; + std::string query = "DELETE VERTEX hash(\"zhangsan\")"; auto result = parser.parse(query); ASSERT_TRUE(result.ok()) << result.status(); }