diff --git a/src/graph/executor/Executor.cpp b/src/graph/executor/Executor.cpp index 1e7de75c27c..e5d5b338212 100644 --- a/src/graph/executor/Executor.cpp +++ b/src/graph/executor/Executor.cpp @@ -342,6 +342,9 @@ Executor *Executor::makeExecutor(QueryContext *qctx, const PlanNode *node) { case PlanNode::Kind::kDeleteVertices: { return pool->add(new DeleteVerticesExecutor(node, qctx)); } + case PlanNode::Kind::kDeleteTags: { + return pool->add(new DeleteTagsExecutor(node, qctx)); + } case PlanNode::Kind::kDeleteEdges: { return pool->add(new DeleteEdgesExecutor(node, qctx)); } diff --git a/src/graph/executor/mutate/DeleteExecutor.cpp b/src/graph/executor/mutate/DeleteExecutor.cpp index 6f943867ffb..cd7dfd15ea0 100644 --- a/src/graph/executor/mutate/DeleteExecutor.cpp +++ b/src/graph/executor/mutate/DeleteExecutor.cpp @@ -75,6 +75,59 @@ folly::Future DeleteVerticesExecutor::deleteVertices() { }); } +folly::Future DeleteTagsExecutor::execute() { + SCOPED_TIMER(&execTime_); + return deleteTags(); +} + +folly::Future DeleteTagsExecutor::deleteTags() { + auto* dtNode = asNode(node()); + const auto& spaceInfo = qctx()->rctx()->session()->space(); + auto vidRef = dtNode->getVidRef(); + DCHECK(vidRef != nullptr); + auto inputVar = dtNode->inputVar(); + DCHECK(!inputVar.empty()); + auto& inputResult = ectx_->getResult(inputVar); + auto iter = inputResult.iter(); + + std::vector delTags; + delTags.reserve(iter->size()); + + QueryExpressionContext ctx(ectx_); + for (; iter->valid(); iter->next()) { + storage::cpp2::DelTags delTag; + DCHECK(!iter->row()->empty()); + auto val = Expression::eval(vidRef, ctx(iter.get())); + if (val.isNull() || val.empty()) { + VLOG(3) << "NULL or EMPTY vid"; + continue; + } + if (!SchemaUtil::isValidVid(val, *spaceInfo.spaceDesc.vid_type_ref())) { + std::stringstream ss; + ss << "Wrong vid type `" << val.type() << "', value `" << val.toString() << "'"; + return Status::Error(ss.str()); + } + delTag.set_id(val); + delTag.set_tags(dtNode->tagIds()); + delTags.emplace_back(std::move(delTag)); + } + + auto spaceId = spaceInfo.id; + time::Duration deleteTagTime; + return qctx() + ->getStorageClient() + ->deleteTags(spaceId, std::move(delTags)) + .via(runner()) + .ensure([deleteTagTime]() { + VLOG(1) << "Delete vertices time: " << deleteTagTime.elapsedInUSec() << "us"; + }) + .thenValue([this](storage::StorageRpcResponse resp) { + SCOPED_TIMER(&execTime_); + NG_RETURN_IF_ERROR(handleCompleteness(resp, false)); + return Status::OK(); + }); +} + folly::Future DeleteEdgesExecutor::execute() { return deleteEdges(); } folly::Future DeleteEdgesExecutor::deleteEdges() { diff --git a/src/graph/executor/mutate/DeleteExecutor.h b/src/graph/executor/mutate/DeleteExecutor.h index f6f6ca437d1..cb7e636dcde 100644 --- a/src/graph/executor/mutate/DeleteExecutor.h +++ b/src/graph/executor/mutate/DeleteExecutor.h @@ -23,6 +23,17 @@ class DeleteVerticesExecutor final : public StorageAccessExecutor { folly::Future deleteVertices(); }; +class DeleteTagsExecutor final : public StorageAccessExecutor { + public: + DeleteTagsExecutor(const PlanNode *node, QueryContext *qctx) + : StorageAccessExecutor("DeleteTagsExecutor", node, qctx) {} + + folly::Future execute() override; + + private: + folly::Future deleteTags(); +}; + class DeleteEdgesExecutor final : public StorageAccessExecutor { public: DeleteEdgesExecutor(const PlanNode *node, QueryContext *qctx) diff --git a/src/graph/planner/plan/Mutate.cpp b/src/graph/planner/plan/Mutate.cpp index f346406fa5e..c5faa79ecbf 100644 --- a/src/graph/planner/plan/Mutate.cpp +++ b/src/graph/planner/plan/Mutate.cpp @@ -73,6 +73,14 @@ std::unique_ptr DeleteVertices::explain() const { return desc; } +std::unique_ptr DeleteTags::explain() const { + auto desc = SingleInputNode::explain(); + addDescription("space", folly::to(space_), desc.get()); + addDescription("vidRef", vidRef_ ? vidRef_->toString() : "", desc.get()); + addDescription("delTags", folly::toJson(util::toJson(tagIds_)), desc.get()); + return desc; +} + std::unique_ptr DeleteEdges::explain() const { auto desc = SingleInputNode::explain(); addDescription("space", folly::to(space_), desc.get()); diff --git a/src/graph/planner/plan/Mutate.h b/src/graph/planner/plan/Mutate.h index 3a319fbaa80..5c914edc8fc 100644 --- a/src/graph/planner/plan/Mutate.h +++ b/src/graph/planner/plan/Mutate.h @@ -322,6 +322,41 @@ class DeleteVertices final : public SingleInputNode { Expression* vidRef_{nullptr}; }; +class DeleteTags final : public SingleInputNode { + public: + static DeleteTags* make(QueryContext* qctx, + PlanNode* input, + GraphSpaceID spaceId, + Expression* vidRef, + std::vector tagIds) { + return qctx->objPool()->add(new DeleteTags(qctx, input, spaceId, vidRef, tagIds)); + } + + std::unique_ptr explain() const override; + + GraphSpaceID getSpace() const { return space_; } + + Expression* getVidRef() const { return vidRef_; } + + const std::vector& tagIds() const { return tagIds_; } + + private: + DeleteTags(QueryContext* qctx, + PlanNode* input, + GraphSpaceID spaceId, + Expression* vidRef, + std::vector tagIds) + : SingleInputNode(qctx, Kind::kDeleteTags, input), + space_(spaceId), + vidRef_(vidRef), + tagIds_(std::move(tagIds)) {} + + private: + GraphSpaceID space_; + Expression* vidRef_{nullptr}; + std::vector tagIds_; +}; + class DeleteEdges final : public SingleInputNode { public: static DeleteEdges* make(QueryContext* qctx, diff --git a/src/graph/planner/plan/PlanNode.cpp b/src/graph/planner/plan/PlanNode.cpp index ac354caf92a..17227d4bb98 100644 --- a/src/graph/planner/plan/PlanNode.cpp +++ b/src/graph/planner/plan/PlanNode.cpp @@ -201,6 +201,8 @@ const char* PlanNode::toString(PlanNode::Kind kind) { return "InnerJoin"; case Kind::kDeleteVertices: return "DeleteVertices"; + case Kind::kDeleteTags: + return "DeleteTags"; case Kind::kDeleteEdges: return "DeleteEdges"; case Kind::kUpdateVertex: diff --git a/src/graph/planner/plan/PlanNode.h b/src/graph/planner/plan/PlanNode.h index faa960775d3..3f09c74b49d 100644 --- a/src/graph/planner/plan/PlanNode.h +++ b/src/graph/planner/plan/PlanNode.h @@ -132,6 +132,7 @@ class PlanNode { kDeleteVertices, kDeleteEdges, kUpdateVertex, + kDeleteTags, kUpdateEdge, // Show diff --git a/src/graph/service/PermissionCheck.cpp b/src/graph/service/PermissionCheck.cpp index 9d77136817e..8cff71fb483 100644 --- a/src/graph/service/PermissionCheck.cpp +++ b/src/graph/service/PermissionCheck.cpp @@ -114,6 +114,7 @@ Status PermissionCheck::permissionCheck(ClientSession *session, case Sentence::Kind::kInsertEdges: case Sentence::Kind::kUpdateEdge: case Sentence::Kind::kDeleteVertices: + case Sentence::Kind::kDeleteTags: case Sentence::Kind::kDeleteEdges: { return PermissionManager::canWriteData(session, vctx); } diff --git a/src/graph/validator/MutateValidator.cpp b/src/graph/validator/MutateValidator.cpp index 622e8059da6..e98701f29fa 100644 --- a/src/graph/validator/MutateValidator.cpp +++ b/src/graph/validator/MutateValidator.cpp @@ -385,6 +385,81 @@ Status DeleteVerticesValidator::toPlan() { return Status::OK(); } +Status DeleteTagsValidator::validateImpl() { + auto sentence = static_cast(sentence_); + spaceId_ = vctx_->whichSpace().id; + + if (sentence->vertices()->isRef()) { + vidRef_ = sentence->vertices()->ref(); + auto type = deduceExprType(vidRef_); + NG_RETURN_IF_ERROR(type); + if (type.value() != vidType_) { + std::stringstream ss; + ss << "The vid `" << vidRef_->toString() << "' should be type of `" << vidType_ + << "', but was`" << type.value() << "'"; + return Status::SemanticError(ss.str()); + } + } else { + auto vIds = sentence->vertices()->vidList(); + for (auto vId : vIds) { + auto idStatus = SchemaUtil::toVertexID(vId, vidType_); + NG_RETURN_IF_ERROR(idStatus); + vertices_.emplace_back(std::move(idStatus).value()); + } + } + + if (!sentence->isAllTag()) { + auto tags = sentence->tags()->labels(); + for (const auto &tag : tags) { + auto tagStatus = qctx_->schemaMng()->toTagID(space_.id, *tag); + NG_RETURN_IF_ERROR(tagStatus); + auto tagId = tagStatus.value(); + tagIds_.emplace_back(tagId); + } + } else { + const auto allTagsResult = qctx_->schemaMng()->getAllLatestVerTagSchema(space_.id); + NG_RETURN_IF_ERROR(allTagsResult); + const auto allTags = std::move(allTagsResult).value(); + for (const auto &tag : allTags) { + tagIds_.emplace_back(tag.first); + } + } + return Status::OK(); +} + +std::string DeleteTagsValidator::buildVIds() { + auto input = vctx_->anonVarGen()->getVar(); + DataSet ds; + ds.colNames.emplace_back(kVid); + for (auto &vid : vertices_) { + Row row; + row.values.emplace_back(vid); + ds.rows.emplace_back(std::move(row)); + } + qctx_->ectx()->setResult(input, ResultBuilder().value(Value(std::move(ds))).finish()); + auto *pool = qctx_->objPool(); + auto *vIds = VariablePropertyExpression::make(pool, input, kVid); + vidRef_ = vIds; + return input; +} + +Status DeleteTagsValidator::toPlan() { + std::string vIdVar; + if (!vertices_.empty() && vidRef_ == nullptr) { + vIdVar = buildVIds(); + } else if (vidRef_ != nullptr && vidRef_->kind() == Expression::Kind::kVarProperty) { + vIdVar = static_cast(vidRef_)->sym(); + } else if (vidRef_ != nullptr && vidRef_->kind() == Expression::Kind::kInputProperty) { + vIdVar = inputVarName_; + } + auto *dedupNode = Dedup::make(qctx_, nullptr); + dedupNode->setInputVar(vIdVar); + auto *dtNode = DeleteTags::make(qctx_, dedupNode, spaceId_, vidRef_, tagIds_); + root_ = dtNode; + tail_ = dedupNode; + return Status::OK(); +} + Status DeleteEdgesValidator::validateImpl() { auto sentence = static_cast(sentence_); auto spaceId = vctx_->whichSpace().id; diff --git a/src/graph/validator/MutateValidator.h b/src/graph/validator/MutateValidator.h index c7e37a0c380..8ebd2a876df 100644 --- a/src/graph/validator/MutateValidator.h +++ b/src/graph/validator/MutateValidator.h @@ -85,6 +85,26 @@ class DeleteVerticesValidator final : public Validator { std::vector edgeKeyRefs_; }; +class DeleteTagsValidator final : public Validator { + public: + DeleteTagsValidator(Sentence* sentence, QueryContext* context) : Validator(sentence, context) {} + + private: + Status validateImpl() override; + + std::string buildVIds(); + + Status toPlan() override; + + private: + GraphSpaceID spaceId_{-1}; + // From ConstantExpression + std::vector vertices_; + // From InputPropertyExpression or InputPropertyExpression + Expression* vidRef_{nullptr}; + std::vector tagIds_; +}; + class DeleteEdgesValidator final : public Validator { public: DeleteEdgesValidator(Sentence* sentence, QueryContext* context) : Validator(sentence, context) {} diff --git a/src/graph/validator/Validator.cpp b/src/graph/validator/Validator.cpp index 18f8a8ad0d2..19197196040 100644 --- a/src/graph/validator/Validator.cpp +++ b/src/graph/validator/Validator.cpp @@ -146,6 +146,8 @@ std::unique_ptr Validator::makeValidator(Sentence* sentence, QueryCon return std::make_unique(sentence, context); case Sentence::Kind::kDeleteVertices: return std::make_unique(sentence, context); + case Sentence::Kind::kDeleteTags: + return std::make_unique(sentence, context); case Sentence::Kind::kDeleteEdges: return std::make_unique(sentence, context); case Sentence::Kind::kUpdateVertex: diff --git a/src/parser/MutateSentences.cpp b/src/parser/MutateSentences.cpp index b1919f540a3..9ff1a313e99 100644 --- a/src/parser/MutateSentences.cpp +++ b/src/parser/MutateSentences.cpp @@ -254,6 +254,20 @@ std::string DeleteVerticesSentence::toString() const { return buf; } +std::string DeleteTagsSentence::toString() const { + std::string buf; + buf.reserve(256); + buf += "DELETE TAG "; + if (tags_->empty()) { + buf += "*"; + } else { + buf += tags_->toString(); + } + buf += " FROM "; + buf += vertices_->toString(); + return buf; +} + std::string DeleteEdgesSentence::toString() const { std::string buf; buf.reserve(256); diff --git a/src/parser/MutateSentences.h b/src/parser/MutateSentences.h index 0e4c74630de..a30cf8adc3e 100644 --- a/src/parser/MutateSentences.h +++ b/src/parser/MutateSentences.h @@ -420,6 +420,45 @@ class DeleteVerticesSentence final : public Sentence { std::unique_ptr vertices_; }; +class DeleteTagsSentence final : public Sentence { + public: + DeleteTagsSentence(VertexIDList *vidList, NameLabelList *labelList) { + kind_ = Kind::kDeleteTags; + vertices_.reset(new VerticesClause(vidList)); + tags_.reset(labelList); + } + + explicit DeleteTagsSentence(VertexIDList *vidList) { + kind_ = Kind::kDeleteTags; + vertices_.reset(new VerticesClause(vidList)); + tags_ = std::make_unique(); + } + + DeleteTagsSentence(Expression *ref, NameLabelList *labelList) { + kind_ = Kind::kDeleteTags; + vertices_.reset(new VerticesClause(ref)); + tags_.reset(labelList); + } + + explicit DeleteTagsSentence(Expression *ref) { + kind_ = Kind::kDeleteTags; + vertices_.reset(new VerticesClause(ref)); + tags_ = std::make_unique(); + } + + const VerticesClause *vertices() const { return vertices_.get(); } + + const NameLabelList *tags() const { return tags_.get(); } + + bool isAllTag() { return tags_->empty(); } + + std::string toString() const override; + + private: + std::unique_ptr vertices_; + std::unique_ptr tags_; +}; + class DeleteEdgesSentence final : public Sentence { public: DeleteEdgesSentence(std::string *edge, EdgeKeys *keys) { diff --git a/src/parser/Sentence.h b/src/parser/Sentence.h index ae914f532b8..da29e8a6f00 100644 --- a/src/parser/Sentence.h +++ b/src/parser/Sentence.h @@ -81,6 +81,7 @@ class Sentence { kShowTSClients, kShowFTIndexes, kDeleteVertices, + kDeleteTags, kDeleteEdges, kLookup, kCreateSpace, diff --git a/src/parser/parser.yy b/src/parser/parser.yy index 862cd6d97b1..961986b1b49 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -363,7 +363,7 @@ static constexpr size_t kCommentLengthLimit = 256; %type mutate_sentence %type insert_vertex_sentence insert_edge_sentence -%type delete_vertex_sentence delete_edge_sentence +%type delete_vertex_sentence delete_edge_sentence delete_tag_sentence %type update_vertex_sentence update_edge_sentence %type download_sentence ingest_sentence @@ -2548,6 +2548,7 @@ traverse_sentence | yield_sentence { $$ = $1; } | get_subgraph_sentence { $$ = $1; } | delete_vertex_sentence { $$ = $1; } + | delete_tag_sentence { $$ = $1; } | delete_edge_sentence { $$ = $1; } | show_queries_sentence { $$ = $1; } | kill_query_sentence { $$ = $1; } @@ -2806,6 +2807,25 @@ delete_vertex_sentence } ; +delete_tag_sentence + : KW_DELETE KW_TAG name_label_list KW_FROM vid_list { + auto sentence = new DeleteTagsSentence($5, $3); + $$ = sentence; + } + | KW_DELETE KW_TAG STAR KW_FROM vid_list { + auto sentence = new DeleteTagsSentence($5); + $$ = sentence; + } + | KW_DELETE KW_TAG name_label_list KW_FROM vid_ref_expression { + auto sentence = new DeleteTagsSentence($5, $3); + $$ = sentence; + } + | KW_DELETE KW_TAG STAR KW_FROM vid_ref_expression { + auto sentence = new DeleteTagsSentence($5); + $$ = sentence; + } + ; + download_sentence : KW_DOWNLOAD KW_HDFS STRING { auto sentence = new DownloadSentence(); diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp index 23dcb18cbdd..67f6595c469 100644 --- a/src/parser/test/ParserTest.cpp +++ b/src/parser/test/ParserTest.cpp @@ -1105,6 +1105,31 @@ TEST_F(ParserTest, DeleteVertex) { auto result = parse(query); ASSERT_TRUE(result.ok()) << result.status(); } + { + std::string query = "DELETE TAG t1 FROM \"Tom\""; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "DELETE TAG t1, t2 FROM \"Tom\""; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "DELETE TAG * FROM \"Tom\""; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "DELETE TAG t1, t2 FROM \"Tom\", \"Jerry\""; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } + { + std::string query = "DELETE TAG * FROM \"Tom\", \"Jerry\""; + auto result = parse(query); + ASSERT_TRUE(result.ok()) << result.status(); + } { std::string query = "GO FROM \"Ann\" OVER schoolmate YIELD $$.person.name as name" diff --git a/tests/tck/features/delete/DeleteTag.IntVid.feature b/tests/tck/features/delete/DeleteTag.IntVid.feature new file mode 100644 index 00000000000..2b10710ef8a --- /dev/null +++ b/tests/tck/features/delete/DeleteTag.IntVid.feature @@ -0,0 +1,305 @@ +# 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. +Feature: Delete int vid of tag + + Scenario: delete int vid one vertex one tag + Given an empty graph + And load "nba_int_vid" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON bachelor hash("Tim Duncan") YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + | "Tim Duncan" | + # delete one tag + When executing query: + """ + DELETE TAG player FROM hash("Tim Duncan"); + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON bachelor hash("Tim Duncan") YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + Then drop the used space + + Scenario: delete int vid one vertex multiple tag + Given an empty graph + And load "nba_int_vid" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON bachelor hash("Tim Duncan") YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + | "Tim Duncan" | + # delete one tag + When executing query: + """ + DELETE TAG player, bachelor FROM hash("Tim Duncan"); + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON bachelor hash("Tim Duncan") YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | bachelor.name | bachelor.speciality | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + Then drop the used space + + Scenario: delete int vid one vertex all tag + Given an empty graph + And load "nba_int_vid" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON bachelor hash("Tim Duncan") YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + | "Tim Duncan" | + # delete one tag + When executing query: + """ + DELETE TAG * FROM hash("Tim Duncan"); + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON bachelor hash("Tim Duncan") YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | bachelor.name | bachelor.speciality | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + Then drop the used space + + Scenario: delete int vid multiple vertex one tag + Given an empty graph + And load "nba_int_vid" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON player hash("Tony Parker") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + | "Tony Parker" | "Tony Parker" | 36 | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + | "Tim Duncan" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tony Parker" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + | "Tony Parker" | + # delete one tag + When executing query: + """ + DELETE TAG player FROM hash("Tim Duncan"), hash("Tony Parker"); + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player hash("Tim Duncan") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON player hash("Tony Parker") YIELD player.name, player.age + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | player.name | player.age | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tony Parker" + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | + Then drop the used space + + Scenario: delete int vid from pipe + Given an empty graph + And load "nba_int_vid" csv data to a new space + # before delete tag + When executing query: + """ + GO FROM hash("Tim Duncan") OVER serve YIELD serve._dst as id + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | id | + | "Spurs" | + When executing query: + """ + FETCH PROP ON team hash("Spurs") YIELD team.name + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | team.name | + | "Spurs" | "Spurs" | + # delete one tag + When executing query: + """ + GO FROM hash("Tim Duncan") OVER serve YIELD serve._dst as id | DELETE TAG team FROM $-.id + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON team hash("Spurs") YIELD team.name + """ + Then the result should be, in any order: + | VertexID | team.name | + # delete tag from pipe and normal + When executing query: + """ + GO FROM hash("Tim Duncan") OVER serve YIELD serve._dst as id | DELETE TAG team FROM $-.id, hash("Lakers") + """ + Then a SyntaxError should be raised at runtime. + Then drop the used space + + Scenario: delete int vid from var + Given an empty graph + And load "nba_int_vid" csv data to a new space + # before delete tag + When executing query: + """ + GO FROM hash("Tim Duncan") OVER serve YIELD serve._dst as id + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | id | + | "Spurs" | + When executing query: + """ + FETCH PROP ON team hash("Spurs") YIELD team.name + """ + Then the result should be, in any order, and the columns 0 should be hashed: + | VertexID | team.name | + | "Spurs" | "Spurs" | + # delete one tag + When executing query: + """ + $var = GO FROM hash("Tim Duncan") OVER serve YIELD serve._dst as id; DELETE TAG team FROM $var.id + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON team hash("Spurs") YIELD team.name + """ + Then the result should be, in any order: + | VertexID | team.name | + # delete one tag from var and normal + When executing query: + """ + $var = GO FROM hash("Tim Duncan") OVER serve YIELD serve._dst as id; DELETE TAG team FROM $var.id, hash("Lakers") + """ + Then a SyntaxError should be raised at runtime. + Then drop the used space diff --git a/tests/tck/features/delete/DeleteTag.feature b/tests/tck/features/delete/DeleteTag.feature new file mode 100644 index 00000000000..e73b5ae62a2 --- /dev/null +++ b/tests/tck/features/delete/DeleteTag.feature @@ -0,0 +1,305 @@ +# 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. +Feature: Delete string vid of tag + + Scenario: delete string vid one vertex one tag + Given an empty graph + And load "nba" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON bachelor "Tim Duncan" YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + | "Tim Duncan" | + # delete one tag + When executing query: + """ + DELETE TAG player FROm "Tim Duncan"; + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON bachelor "Tim Duncan" YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + Then drop the used space + + Scenario: delete string vid one vertex multiple tag + Given an empty graph + And load "nba" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON bachelor "Tim Duncan" YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + | "Tim Duncan" | + # delete one tag + When executing query: + """ + DELETE TAG player, bachelor FROM "Tim Duncan"; + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON bachelor "Tim Duncan" YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order: + | VertexID | bachelor.name | bachelor.speciality | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + Then drop the used space + + Scenario: delete string vid one vertex all tag + Given an empty graph + And load "nba" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON bachelor "Tim Duncan" YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order: + | VertexID | bachelor.name | bachelor.speciality | + | "Tim Duncan" | "Tim Duncan" | "psychology" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + | "Tim Duncan" | + # delete one tag + When executing query: + """ + DELETE TAG * FROM "Tim Duncan"; + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON bachelor "Tim Duncan" YIELD bachelor.name, bachelor.speciality + """ + Then the result should be, in any order: + | VertexID | bachelor.name | bachelor.speciality | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + Then drop the used space + + Scenario: delete string vid multiple vertex one tag + Given an empty graph + And load "nba" csv data to a new space + # before delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + | "Tim Duncan" | "Tim Duncan" | 42 | + When executing query: + """ + FETCH PROP ON player "Tony Parker" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + | "Tony Parker" | "Tony Parker" | 36 | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + | "Tim Duncan" | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tony Parker" + """ + Then the result should be, in any order: + | VertexID | + | "Tony Parker" | + # delete one tag + When executing query: + """ + DELETE TAG player FROM "Tim Duncan", "Tony Parker"; + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON player "Tim Duncan" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + When executing query: + """ + FETCH PROP ON player "Tony Parker" YIELD player.name, player.age + """ + Then the result should be, in any order: + | VertexID | player.name | player.age | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tim Duncan" + """ + Then the result should be, in any order: + | VertexID | + When executing query: + """ + LOOKUP ON player WHERE player.name == "Tony Parker" + """ + Then the result should be, in any order: + | VertexID | + Then drop the used space + + Scenario: delete string vid from pipe + Given an empty graph + And load "nba" csv data to a new space + # before delete tag + When executing query: + """ + GO FROM "Tim Duncan" OVER serve YIELD serve._dst as id + """ + Then the result should be, in any order: + | id | + | "Spurs" | + When executing query: + """ + FETCH PROP ON team "Spurs" YIELD team.name + """ + Then the result should be, in any order: + | VertexID | team.name | + | "Spurs" | "Spurs" | + # delete one tag + When executing query: + """ + GO FROM "Tim Duncan" OVER serve YIELD serve._dst as id | DELETE TAG team FROM $-.id + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON team "Spurs" YIELD team.name + """ + Then the result should be, in any order: + | VertexID | team.name | + # delete tag from pipe and normal + When executing query: + """ + GO FROM "Tim Duncan" OVER serve YIELD serve._dst as id | DELETE TAG team FROM $-.id, "Lakers" + """ + Then a SyntaxError should be raised at runtime. + Then drop the used space + + Scenario: delete string vid from var + Given an empty graph + And load "nba" csv data to a new space + # before delete tag + When executing query: + """ + GO FROM "Tim Duncan" OVER serve YIELD serve._dst as id + """ + Then the result should be, in any order: + | id | + | "Spurs" | + When executing query: + """ + FETCH PROP ON team "Spurs" YIELD team.name + """ + Then the result should be, in any order: + | VertexID | team.name | + | "Spurs" | "Spurs" | + # delete one tag + When executing query: + """ + $var = GO FROM "Tim Duncan" OVER serve YIELD serve._dst as id; DELETE TAG team FROM $var.id + """ + Then the execution should be successful + # after delete tag + When executing query: + """ + FETCH PROP ON team "Spurs" YIELD team.name + """ + Then the result should be, in any order: + | VertexID | team.name | + # delete one tag from var and normal + When executing query: + """ + $var = GO FROM "Tim Duncan" OVER serve YIELD serve._dst as id; DELETE TAG team FROM $var.id, "Lakers" + """ + Then a SyntaxError should be raised at runtime. + Then drop the used space