Skip to content
Snippets Groups Projects
Commit f1384d44 authored by Simon Liu's avatar Simon Liu Committed by dangleptr
Browse files

Issue#192 Support multiple edge types in GO statement (#699)

*     Issue#192 Support multiple edge types in GO statement

Summary:
Implemented over multiple edge types(include over "*" ) for Support all edge type in Go statement.

1. Modification of the storage interface:
   1.1 Modify the GetNeighborsRequest structure, pass a list of edge_type to the storage layer.
   1.2 And add an over_all_edges tag to mark "over *".
       Modify the PropDef structure to represent both tag_id and edge_type
   1.3 Added the EdgeData structure to represent the edge data returned to the client.
2. When the yield statement does not exist, rename the "_dst" attribute of edge to edge_name+"_id"
3. Delete the getOutBound and getInBound interfaces,
   because the edges passed to the storage may have both in and out.
4  Added a map of edge type to edge name for metaclien (toEdgeName)

PS:
There are still two issues that need to be implemented.
1 Since we are not implementing a null type, we cannot represent some non-existing attributes.
2 Due to the existence of 1, there is currently no judgment on the attributes of the edges and the vetex.
So when returning multiple types of vetex/edge,
the same result will be returned if the attribute names are the same("MULTI_EDGES" test in GoTest.cpp).

* 1. add more test.
2. Solved the problem of display when some properties are not present(return the default value to the user).

for example:
type             default
int              0
bool             false
double/float     0.0

* format the code style.

* 1. When yield does not exist, don't implicitly rename _dst prop.
2. format some code style.

* Fixed an problem where the results might be incorrect when using multiple edges with filter.

* Modify the storage interface to move the schema from tagdata/edgedata to QueryResponse.

* Address dangleptr's and wadeliuyi's comments.

*  Address dangleptr's and laura's comments.

* Address laura's comments.

*      Address dangleptr's comments.

* Address dangleptr's comments.

* Address dangleptr's comments.

* fixed the unit test failed(go_test and orderbytest).
parent f3951ce3
No related branches found
No related tags found
No related merge requests found
......@@ -5,7 +5,7 @@
*/
#ifndef GRAPH_DELETEVERTEXEXECUTOR_H_
#define GRAPH_DELETEVERTEXEEXECUTOR_H_
#define GRAPH_DELETEVERTEXEXECUTOR_H_
#include "base/Base.h"
#include "graph/Executor.h"
......
......@@ -244,7 +244,14 @@ Status FetchEdgesExecutor::setupEdgeKeysFromExpr() {
}
void FetchEdgesExecutor::fetchEdges() {
auto props = getPropNames();
std::vector<storage::cpp2::PropDef> props;
auto status = getPropNames(props);
if (!status.ok()) {
DCHECK(onError_);
onError_(status);
return;
}
if (props.empty()) {
DCHECK(onError_);
onError_(Status::Error("No props declared."));
......@@ -276,16 +283,21 @@ void FetchEdgesExecutor::fetchEdges() {
std::move(future).via(runner).thenValue(cb).thenError(error);
}
std::vector<storage::cpp2::PropDef> FetchEdgesExecutor::getPropNames() {
std::vector<storage::cpp2::PropDef> props;
Status FetchEdgesExecutor::getPropNames(std::vector<storage::cpp2::PropDef> &props) {
for (auto &prop : expCtx_->aliasProps()) {
storage::cpp2::PropDef pd;
pd.owner = storage::cpp2::PropOwner::EDGE;
pd.name = prop.second;
auto status = ectx()->schemaManager()->toEdgeType(spaceId_, prop.first);
if (!status.ok()) {
return Status::Error("No schema found for '%s'", prop.first.c_str());
}
auto edgeType = status.value();
pd.id.set_edge_type(edgeType);
props.emplace_back(std::move(pd));
}
return props;
return Status::OK();
}
void FetchEdgesExecutor::processResult(RpcResponse &&result) {
......
......@@ -38,7 +38,7 @@ private:
Status setupEdgeKeysFromRef();
std::vector<storage::cpp2::PropDef> getPropNames();
Status getPropNames(std::vector<storage::cpp2::PropDef> &props);
void fetchEdges();
......
......@@ -148,7 +148,7 @@ std::vector<storage::cpp2::PropDef> FetchVerticesExecutor::getPropNames() {
storage::cpp2::PropDef pd;
pd.owner = storage::cpp2::PropOwner::SOURCE;
pd.name = prop.second;
pd.tag_id = tagID_;
pd.id.set_tag_id(tagID_);
props.emplace_back(std::move(pd));
}
......@@ -161,17 +161,30 @@ void FetchVerticesExecutor::processResult(RpcResponse &&result) {
std::unique_ptr<RowSetWriter> rsWriter;
auto uniqResult = std::make_unique<std::unordered_set<std::string>>();
for (auto &resp : all) {
if (!resp.__isset.vertices || !resp.__isset.vertex_schema
|| resp.get_vertices() == nullptr || resp.get_vertex_schema() == nullptr) {
if (!resp.__isset.vertices) {
continue;
}
auto vschema = std::make_shared<ResultSchemaProvider>(resp.vertex_schema);
auto *schema = resp.get_vertex_schema();
if (schema == nullptr) {
continue;
}
std::unordered_map<TagID, std::shared_ptr<ResultSchemaProvider>> tagSchema;
std::transform(schema->cbegin(), schema->cend(),
std::inserter(tagSchema, tagSchema.begin()), [](auto &s) {
return std::make_pair(
s.first, std::make_shared<ResultSchemaProvider>(s.second));
});
for (auto &vdata : resp.vertices) {
std::unique_ptr<RowReader> vreader;
if (!vdata.__isset.vertex_data || vdata.vertex_data.empty()) {
if (!vdata.__isset.tag_data || vdata.tag_data.empty()) {
continue;
}
vreader = RowReader::getRowReader(vdata.vertex_data, vschema);
auto vschema = tagSchema[vdata.tag_data[0].tag_id];
vreader = RowReader::getRowReader(vdata.tag_data[0].data, vschema);
if (outputSchema == nullptr) {
outputSchema = std::make_shared<SchemaWriter>();
auto status = getOutputSchema(vschema.get(), vreader.get(), outputSchema.get());
......@@ -212,7 +225,7 @@ void FetchVerticesExecutor::processResult(RpcResponse &&result) {
rsWriter->addRow(std::move(encode));
}
} // for `vdata'
} // for `resp'
} // for `resp'
finishExecution(std::move(rsWriter));
}
......
This diff is collapsed.
......@@ -57,6 +57,8 @@ private:
Status prepareDistinct();
Status prepareOverAll();
/**
* To check if this is the final step.
*/
......@@ -72,14 +74,6 @@ private:
return upto_;
}
/**
* To check if `REVERSELY' is specified.
* If so, we step out in a reverse manner.
*/
bool isReversely() const {
return reversely_;
}
/**
* To obtain the source ids from various places,
* such as the literal id list, inputs from the pipeline or results of variable.
......@@ -122,6 +116,10 @@ private:
*/
std::vector<VertexID> getDstIdsFromResp(RpcResponse &rpcResp) const;
/**
* get the edgeName from response when over all edges
*/
std::vector<std::string> getEdgeNamesFromResp(RpcResponse &rpcResp) const;
/**
* All required data have arrived, finish the execution.
*/
......@@ -157,23 +155,15 @@ private:
*/
class VertexHolder final {
public:
OptVariantType get(VertexID id, int64_t index) const;
VariantType getDefaultProp(TagID tid, const std::string &prop) const;
OptVariantType get(VertexID id, TagID tid, const std::string &prop) const;
void add(const storage::cpp2::QueryResponse &resp);
nebula::cpp2::SupportedType getType(int64_t index);
const auto* schema() const {
return schema_.get();
}
nebula::cpp2::SupportedType getDefaultPropType(TagID tid, const std::string &prop) const;
nebula::cpp2::SupportedType getType(VertexID id, TagID tid, const std::string &prop);
private:
// The schema include multi vertexes, and multi tags of one vertex
// eg: get 3 vertexex, vertex A has tag1.prop1, vertex B has tag2.prop2,
// vertex C has tag3.prop3,
// and the schema is {[tag1.prop1, type], [tag2.prop2, type], [tag3.prop3, type]}
std::shared_ptr<ResultSchemaProvider> schema_;
std::unordered_map<VertexID, std::string> data_;
using VData = std::tuple<std::shared_ptr<ResultSchemaProvider>, std::string>;
std::unordered_map<VertexID, std::unordered_map<TagID, VData>> data_;
};
class VertexBackTracker final {
......@@ -213,8 +203,7 @@ private:
uint32_t steps_{1};
uint32_t curStep_{1};
bool upto_{false};
bool reversely_{false};
EdgeType edgeType_;
std::vector<EdgeType> edgeTypes_;
std::string *varname_{nullptr};
std::string *colname_{nullptr};
Expression *filter_{nullptr};
......@@ -231,8 +220,6 @@ private:
std::unique_ptr<cpp2::ExecutionResponse> resp_;
// The name of Tag or Edge, index of prop in data
using SchemaPropIndex = std::unordered_map<std::pair<std::string, std::string>, int64_t>;
SchemaPropIndex srcTagProps_;
SchemaPropIndex dstTagProps_;
};
} // namespace graph
......
......@@ -66,8 +66,8 @@ TEST_F(FetchVerticesTest, base) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt = "GO FROM %ld over like "
"| FETCH PROP ON player $- YIELD player.name, player.age";
auto *fmt = "GO FROM %ld over like YIELD like._dst as id"
"| FETCH PROP ON player $-.id YIELD player.name, player.age";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
......@@ -86,7 +86,7 @@ TEST_F(FetchVerticesTest, base) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt = "$var = GO FROM %ld over like;"
auto *fmt = "$var = GO FROM %ld over like YIELD like._dst as id;"
"FETCH PROP ON player $var.id YIELD player.name, player.age";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
......@@ -106,7 +106,7 @@ TEST_F(FetchVerticesTest, base) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt = "$var = GO FROM %ld over like;"
auto *fmt = "$var = GO FROM %ld over like YIELD like._dst as id;"
"FETCH PROP ON player $var.id YIELD player.name as name, player.age"
" | ORDER BY name";
auto query = folly::stringPrintf(fmt, player.vid());
......
......@@ -36,7 +36,7 @@ TEST_F(GoTest, OneStepOutBound) {
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::string> expectedColNames{
{"id"}
{"serve._dst"}
};
ASSERT_TRUE(verifyColNames(resp, expectedColNames));
......@@ -94,14 +94,14 @@ TEST_F(GoTest, OneStepOutBound) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt = "GO FROM %ld OVER like "
"| GO FROM $-.id OVER like | GO FROM $-.id OVER serve";
auto *fmt = "GO FROM %ld OVER like YIELD like._dst as id"
"| GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::string> expectedColNames{
{"id"}
{"serve._dst"}
};
ASSERT_TRUE(verifyColNames(resp, expectedColNames));
......@@ -119,14 +119,15 @@ TEST_F(GoTest, OneStepOutBound) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt = "GO FROM %ld OVER like "
"| ( GO FROM $-.id OVER like | GO FROM $-.id OVER serve )";
auto *fmt =
"GO FROM %ld OVER like YIELD like._dst as id"
"| ( GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve )";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::string> expectedColNames{
{"id"}
{"serve._dst"}
};
ASSERT_TRUE(verifyColNames(resp, expectedColNames));
......@@ -148,14 +149,14 @@ TEST_F(GoTest, AssignmentSimple) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Tracy McGrady"];
auto *fmt = "$var = GO FROM %ld OVER like; "
auto *fmt = "$var = GO FROM %ld OVER like YIELD like._dst as id; "
"GO FROM $var.id OVER like";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::string> expectedColNames{
{"id"}
{"like._dst"}
};
ASSERT_TRUE(verifyColNames(resp, expectedColNames));
......@@ -172,14 +173,16 @@ TEST_F(GoTest, AssignmentPipe) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Tracy McGrady"];
auto *fmt = "$var = (GO FROM %ld OVER like | GO FROM $- OVER like);"
"GO FROM $var OVER like";
auto *fmt =
"$var = (GO FROM %ld OVER like YIELD like._dst as id | GO FROM $-.id OVER like YIELD "
"like._dst as id);"
"GO FROM $var.id OVER like";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::string> expectedColNames{
{"id"}
{"like._dst"}
};
ASSERT_TRUE(verifyColNames(resp, expectedColNames));
......@@ -208,7 +211,7 @@ TEST_F(GoTest, VariableUndefined) {
TEST_F(GoTest, AssignmentEmptyResult) {
{
cpp2::ExecutionResponse resp;
auto query = "$var = GO FROM -1 OVER like; "
auto query = "$var = GO FROM -1 OVER like YIELD like._dst as id; "
"GO FROM $var.id OVER like";
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
......@@ -242,7 +245,7 @@ TEST_F(GoTest, DISABLED_OneStepInOutBound) {
// Ever served in the same team
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER serve | GO FROM $-.id OVER serve REVERSELY";
auto *fmt = "GO FROM %ld OVER serve | GO FROM $-.serve_id OVER serve REVERSELY";
auto &player = players_["Kobe Bryant"];
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
......@@ -273,8 +276,8 @@ TEST_F(GoTest, Distinct) {
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt = "GO FROM %ld OVER like "
"| GO FROM $-.id OVER like | GO FROM $-.id OVER serve "
auto *fmt = "GO FROM %ld OVER like YIELD like._dst as id"
"| GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve "
"YIELD DISTINCT serve._dst, $$.team.name";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
......@@ -335,7 +338,7 @@ TEST_F(GoTest, VertexNotExist) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER serve | GO FROM $-.id OVER serve";
auto *fmt = "GO FROM %ld OVER serve | GO FROM $-.serve_id OVER serve";
auto query = folly::stringPrintf(fmt, nonExistPlayerID);
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
......@@ -343,8 +346,8 @@ TEST_F(GoTest, VertexNotExist) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER like "
"| GO FROM $-.id OVER like | GO FROM $-.id OVER serve";
auto *fmt = "GO FROM %ld OVER like YIELD like._dst as id"
"| GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve";
auto query = folly::stringPrintf(fmt, nonExistPlayerID);
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
......@@ -352,8 +355,8 @@ TEST_F(GoTest, VertexNotExist) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER like "
"| (GO FROM $-.id OVER like | GO FROM $-.id OVER serve)";
auto *fmt = "GO FROM %ld OVER like YIELD like._dst as id"
"| (GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve)";
auto query = folly::stringPrintf(fmt, nonExistPlayerID);
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
......@@ -361,6 +364,133 @@ TEST_F(GoTest, VertexNotExist) {
}
}
TEST_F(GoTest, MULTI_EDGES) {
// Ever served in the same team
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER serve, like";
auto &player = players_["Russell Westbrook"];
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::tuple<int64_t, int64_t>> expected = {
{teams_["Thunders"].vid(), 0},
{0, players_["Paul George"].vid()},
{0, players_["James Harden"].vid()},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER serve, like";
auto &player = players_["Shaquile O'Neal"];
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::tuple<int64_t, int64_t>> expected = {
{teams_["Magic"].vid(), 0},
{teams_["Lakers"].vid(), 0},
{teams_["Heat"].vid(), 0},
{teams_["Suns"].vid(), 0},
{teams_["Cavaliers"].vid(), 0},
{teams_["Celtics"].vid(), 0},
{0, players_["JaVale McGee"].vid()},
{0, players_["Tim Duncan"].vid()},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER * YIELD serve._dst, like._dst";
auto &player = players_["Dirk Nowitzki"];
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::tuple<int64_t, int64_t>> expected = {
{teams_["Mavericks"].vid(), 0},
{0, players_["Steve Nash"].vid()},
{0, players_["Jason Kidd"].vid()},
{0, players_["Dwyane Wade"].vid()},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER *";
auto &player = players_["Paul Gasol"];
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::tuple<int64_t, int64_t>> expected = {
{0, teams_["Grizzlies"].vid()}, {0, teams_["Lakers"].vid()},
{0, teams_["Bulls"].vid()}, {0, teams_["Spurs"].vid()},
{0, teams_["Bucks"].vid()}, {players_["Kobe Bryant"].vid(), 0},
{players_["Marc Gasol"].vid(), 0},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER * YIELD $$.team.name, $$.player.name";
auto &player = players_["LaMarcus Aldridge"];
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, std::string>> expected = {
{"Trail Blazers", ""},
{"", "Tim Duncan"},
{"", "Tony Parker"},
{"Spurs", ""},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt =
"GO FROM %ld OVER like, serve YIELD like._dst as id"
"| ( GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve )";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::tuple<int64_t>> expected = {
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Hornets"].vid()},
{teams_["Trail Blazers"].vid()},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
auto &player = players_["Boris Diaw"];
auto *fmt =
"GO FROM %ld OVER * YIELD like._dst as id"
"| ( GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve )";
auto query = folly::stringPrintf(fmt, player.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::tuple<int64_t>> expected = {
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Spurs"].vid()},
{teams_["Hornets"].vid()},
{teams_["Trail Blazers"].vid()},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
}
TEST_F(GoTest, ReferencePipeInYieldAndWhere) {
{
......
......@@ -305,13 +305,15 @@ TEST_F(OrderByTest, InterimResult) {
{
cpp2::ExecutionResponse resp;
auto &boris = players_["Boris Diaw"];
auto *fmt = "GO FROM %ld OVER like | ORDER BY $-.id | GO FROM $-.id over serve";
auto *fmt =
"GO FROM %ld OVER like YIELD like._dst as id | ORDER BY $-.id | GO FROM $-.id over "
"serve";
auto query = folly::stringPrintf(fmt, boris.vid());
auto code = client_->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
std::vector<std::string> expectedColNames{
{"id"}
{"serve._dst"}
};
ASSERT_TRUE(verifyColNames(resp, expectedColNames));
......
......@@ -95,10 +95,11 @@ TEST_F(SetTest, UnionAllTest) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" UNION ALL "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id| "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" UNION ALL "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tim.vid(), tony.vid());
......@@ -128,10 +129,11 @@ TEST_F(SetTest, UnionAllTest) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION ALL "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION ALL "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tim.vid(), tony.vid());
......@@ -161,10 +163,11 @@ TEST_F(SetTest, UnionAllTest) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION ALL "
"(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)";
auto *fmt =
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION ALL "
"(GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tony.vid(), tim.vid());
......@@ -194,10 +197,11 @@ TEST_F(SetTest, UnionAllTest) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION ALL "
"GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION ALL "
"GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tony.vid(), tim.vid());
......@@ -227,9 +231,11 @@ TEST_F(SetTest, UnionAllTest) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like UNION ALL GO FROM %ld OVER like)"
" | GO FROM $- OVER serve"
" YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id UNION ALL GO FROM %ld OVER like YIELD "
"like._dst as id)"
" | GO FROM $-.id OVER serve"
" YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tony.vid(), tim.vid());
......@@ -296,12 +302,13 @@ TEST_F(SetTest, UnionAllTest) {
TEST_F(SetTest, UnionDistinct) {
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" UNION "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" UNION "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto &manu = players_["Manu Ginobili"];
......@@ -327,10 +334,11 @@ TEST_F(SetTest, UnionDistinct) {
}
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" UNION DISTINCT "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" UNION DISTINCT "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tim.vid(), tony.vid());
......@@ -358,10 +366,11 @@ TEST_F(SetTest, UnionDistinct) {
TEST_F(SetTest, Minus) {
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" MINUS "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" MINUS "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tim.vid(), tony.vid());
......@@ -392,10 +401,11 @@ TEST_F(SetTest, Minus) {
TEST_F(SetTest, Intersect) {
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" INTERSECT "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" INTERSECT "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto query = folly::stringPrintf(fmt, tim.vid(), tony.vid());
......@@ -420,14 +430,15 @@ TEST_F(SetTest, Intersect) {
TEST_F(SetTest, Mix) {
{
cpp2::ExecutionResponse resp;
auto *fmt = "(GO FROM %ld OVER like | "
"GO FROM $- OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" MINUS "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" INTERSECT "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto *fmt =
"(GO FROM %ld OVER like YIELD like._dst as id | "
"GO FROM $-.id OVER serve YIELD $^.player.name, serve.start_year, $$.team.name)"
" MINUS "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" UNION "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name"
" INTERSECT "
"GO FROM %ld OVER serve YIELD $^.player.name, serve.start_year, $$.team.name";
auto &tim = players_["Tim Duncan"];
auto &tony = players_["Tony Parker"];
auto &manu = players_["Manu Ginobili"];
......
......@@ -61,10 +61,9 @@ std::string FromClause::toString() const {
}
std::string OverClause::toString() const {
std::string OverEdge::toString() const {
std::string buf;
buf.reserve(256);
buf += "OVER ";
buf += *edge_;
if (alias_ != nullptr) {
buf += " AS ";
......@@ -76,6 +75,26 @@ std::string OverClause::toString() const {
return buf;
}
std::string OverEdges::toString() const {
std::string buf;
buf.reserve(256);
for (auto &e : edges_) {
buf += e->toString();
buf += ",";
}
return buf;
}
std::string OverClause::toString() const {
std::string buf;
buf.reserve(256);
buf += "OVER ";
buf += overEdges_->toString();
return buf;
}
std::string WhereClause::toString() const {
std::string buf;
buf.reserve(256);
......
......@@ -103,37 +103,60 @@ private:
std::unique_ptr<Expression> ref_;
};
class OverClause final {
class OverEdge final {
public:
explicit OverClause(std::string *edge,
std::string *alias = nullptr,
bool isReversely = false) {
explicit OverEdge(std::string *edge, std::string *alias = nullptr, bool isReversely = false) {
edge_.reset(edge);
alias_.reset(alias);
isReversely_ = isReversely;
}
bool isReversely() const {
return isReversely_;
}
bool isReversely() const { return isReversely_; }
std::string* edge() const {
return edge_.get();
}
bool isOverAll() const { return *edge_ == "*"; }
std::string* alias() const {
return alias_.get();
std::string *edge() const { return edge_.get(); }
std::string *alias() const { return alias_.get(); }
std::string toString() const;
private:
bool isReversely_{false};
std::unique_ptr<std::string> edge_;
std::unique_ptr<std::string> alias_;
};
class OverEdges final {
public:
void addEdge(OverEdge *edge) { edges_.emplace_back(edge); }
std::vector<OverEdge *> edges() {
std::vector<OverEdge *> result;
std::transform(edges_.cbegin(), edges_.cend(),
std::insert_iterator<std::vector<OverEdge *>>(result, result.begin()),
[](auto &edge) { return edge.get(); });
return result;
}
std::string toString() const;
private:
bool isReversely_{false};
std::unique_ptr<std::string> edge_;
std::unique_ptr<std::string> alias_;
std::vector<std::unique_ptr<OverEdge>> edges_;
};
class OverClause final {
public:
explicit OverClause(OverEdges *edges) { overEdges_.reset(edges); }
std::vector<OverEdge *> edges() const { return overEdges_->edges(); }
std::string toString() const;
private:
std::unique_ptr<OverEdges> overEdges_;
};
class WhereClause final {
public:
......@@ -216,6 +239,6 @@ private:
bool distinct_;
};
} // namespace nebula
} // namespace nebula
#endif // PARSER_CLAUSES_H_
......@@ -44,6 +44,8 @@ class GraphScanner;
nebula::StepClause *step_clause;
nebula::FromClause *from_clause;
nebula::VertexIDList *vid_list;
nebula::OverEdge *over_edge;
nebula::OverEdges *over_edges;
nebula::OverClause *over_clause;
nebula::WhereClause *where_clause;
nebula::YieldClause *yield_clause;
......@@ -134,6 +136,8 @@ class GraphScanner;
%type <step_clause> step_clause
%type <from_clause> from_clause
%type <vid_list> vid_list
%type <over_edge> over_edge
%type <over_edges> over_edges
%type <over_clause> over_clause
%type <where_clause> where_clause
%type <yield_clause> yield_clause
......@@ -438,12 +442,16 @@ go_sentence
go->setOverClause($4);
go->setWhereClause($5);
if ($6 == nullptr) {
auto *edge = new std::string(*$4->edge());
auto *expr = new EdgeDstIdExpression(edge);
auto *alias = new std::string("id");
auto *col = new YieldColumn(expr, alias);
auto *cols = new YieldColumns();
cols->addColumn(col);
for (auto e : $4->edges()) {
if (e->isOverAll()) {
continue;
}
auto *edge = new std::string(*e->edge());
auto *expr = new EdgeDstIdExpression(edge);
auto *col = new YieldColumn(expr);
cols->addColumn(col);
}
$6 = new YieldClause(cols);
}
go->setYieldClause($6);
......@@ -507,18 +515,50 @@ vid_ref_expression
}
;
over_clause
: KW_OVER name_label {
$$ = new OverClause($2);
over_edge
: name_label {
$$ = new OverEdge($1);
}
| name_label KW_REVERSELY {
$$ = new OverEdge($1, nullptr, true);
}
| KW_OVER name_label KW_REVERSELY {
$$ = new OverClause($2, nullptr, true);
| name_label KW_AS name_label {
$$ = new OverEdge($1, $3);
}
| KW_OVER name_label KW_AS name_label {
$$ = new OverClause($2, $4);
| name_label KW_AS name_label KW_REVERSELY {
$$ = new OverEdge($1, $3, true);
}
| KW_OVER name_label KW_AS name_label KW_REVERSELY {
$$ = new OverClause($2, $4, true);
;
over_edges
: over_edge {
auto edge = new OverEdges();
edge->addEdge($1);
$$ = edge;
}
| over_edges COMMA over_edge {
$1->addEdge($3);
$$ = $1;
}
;
over_clause
: KW_OVER MUL {
auto edges = new OverEdges();
auto s = new std::string("*");
auto edge = new OverEdge(s, nullptr, false);
edges->addEdge(edge);
$$ = new OverClause(edges);
}
| KW_OVER MUL KW_REVERSELY {
auto edges = new OverEdges();
auto s = new std::string("*");
auto edge = new OverEdge(s, nullptr, false);
edges->addEdge(edge);
$$ = new OverClause(edges);
}
| KW_OVER over_edges {
$$ = new OverClause($2);
}
;
......@@ -654,11 +694,11 @@ edge_key_ref:
var_ref_expression R_ARROW var_ref_expression AT var_ref_expression {
$$ = new EdgeKeyRef($1, $3, $5, false);
}
|
|
input_ref_expression R_ARROW input_ref_expression {
$$ = new EdgeKeyRef($1, $3, nullptr);
}
|
|
var_ref_expression R_ARROW var_ref_expression {
$$ = new EdgeKeyRef($1, $3, nullptr, false);
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment