Skip to content
Snippets Groups Projects
Unverified Commit adf3b238 authored by Yichen Wang's avatar Yichen Wang Committed by GitHub
Browse files

refactor keywords (#333)


* refactor keywords

fix

* fix

Co-authored-by: default avatarcpw <13495049+CPWstatic@users.noreply.github.com>
parent 1dc538fc
No related branches found
Tags v3.16-rc1
No related merge requests found
......@@ -148,8 +148,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
%token KW_OUT KW_BOTH KW_SUBGRAPH
%token KW_EXPLAIN KW_PROFILE KW_FORMAT
%token KW_CONTAINS
%token KW_STARTS_WITH
%token KW_ENDS_WITH
%token KW_STARTS KW_ENDS
/* symbols */
%token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE COMMA
......@@ -291,7 +290,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
%left OR KW_OR KW_XOR
%left AND KW_AND
%left EQ NE LT LE GT GE KW_IN KW_NOT_IN KW_CONTAINS KW_NOT_CONTAINS KW_STARTS_WITH KW_ENDS_WITH
%left EQ NE LT LE GT GE KW_IN KW_NOT_IN KW_CONTAINS KW_NOT_CONTAINS KW_STARTS_WITH KW_ENDS_WITH KW_NOT_STARTS_WITH KW_NOT_ENDS_WITH
%left PLUS MINUS
%left STAR DIV MOD
%right NOT KW_NOT
......@@ -369,10 +368,9 @@ unreserved_keyword
| KW_ALL { $$ = new std::string("all"); }
| KW_SHORTEST { $$ = new std::string("shortest"); }
| KW_COUNT_DISTINCT { $$ = new std::string("count_distinct"); }
| KW_NOT_CONTAINS { $$ = new std::string("not_contains"); }
| KW_CONTAINS { $$ = new std::string("contains"); }
| KW_STARTS_WITH { $$ = new std::string("starts_with"); }
| KW_ENDS_WITH { $$ = new std::string("ends_with"); }
| KW_STARTS { $$ = new std::string("starts"); }
| KW_ENDS { $$ = new std::string("ends"); }
| KW_VID_TYPE { $$ = new std::string("vid_type"); }
;
......@@ -470,12 +468,21 @@ expression
| expression KW_CONTAINS expression {
$$ = new RelationalExpression(Expression::Kind::kContains, $1, $3);
}
| expression KW_NOT_CONTAINS expression {
$$ = new RelationalExpression(Expression::Kind::kNotContains, $1, $3);
}
| expression KW_STARTS_WITH expression {
$$ = new RelationalExpression(Expression::Kind::kStartsWith, $1, $3);
}
| expression KW_NOT_STARTS_WITH expression {
$$ = new RelationalExpression(Expression::Kind::kNotStartsWith, $1, $3);
}
| expression KW_ENDS_WITH expression {
$$ = new RelationalExpression(Expression::Kind::kEndsWith, $1, $3);
}
| expression KW_NOT_ENDS_WITH expression {
$$ = new RelationalExpression(Expression::Kind::kNotEndsWith, $1, $3);
}
| expression EQ expression {
$$ = new RelationalExpression(Expression::Kind::kRelEQ, $1, $3);
}
......
......@@ -170,8 +170,12 @@ BOTH ([Bb][Oo][Tt][Hh])
SUBGRAPH ([Ss][Uu][Bb][Gg][Rr][Aa][Pp][Hh])
CONTAINS ([Cc][Oo][Nn][Tt][Aa][Ii][Nn][Ss])
NOT_CONTAINS ({NOT}{blanks}{CONTAINS})
STARTS_WITH ([Ss][Tt][Aa][Rr][Tt][Ss]{blanks}[Ww][Ii][Tt][Hh])
ENDS_WITH ([Ee][Nn][Dd][Ss]{blanks}[Ww][Ii][Tt][Hh])
STARTS ([Ss][Tt][Aa][Rr][Tt][Ss])
STARTS_WITH ({STARTS}{blanks}{WITH})
NOT_STARTS_WITH ({NOT}{blanks}{STARTS}{blanks}{WITH})
ENDS ([Ee][Nn][Dd][Ss])
ENDS_WITH ({ENDS}{blanks}{WITH})
NOT_ENDS_WITH ({NOT}{blanks}{ENDS}{blanks}{WITH})
LABEL ([a-zA-Z][_a-zA-Z0-9]*)
DEC ([0-9])
......@@ -342,8 +346,12 @@ FORMAT ([Ff][Oo][Rr][Mm][Aa][Tt])
{SUBGRAPH} { return TokenType::KW_SUBGRAPH; }
{CONTAINS} { return TokenType::KW_CONTAINS; }
{NOT_CONTAINS} { return TokenType::KW_NOT_CONTAINS; }
{STARTS} { return TokenType::KW_STARTS;}
{STARTS_WITH} { return TokenType::KW_STARTS_WITH;}
{NOT_STARTS_WITH} { return TokenType::KW_NOT_STARTS_WITH;}
{ENDS} { return TokenType::KW_ENDS;}
{ENDS_WITH} { return TokenType::KW_ENDS_WITH;}
{NOT_ENDS_WITH} { return TokenType::KW_NOT_ENDS_WITH;}
{TRUE} { yylval->boolval = true; return TokenType::BOOL; }
......
......@@ -414,6 +414,12 @@ TEST(Scanner, Basic) {
CHECK_SEMANTIC_TYPE("CONTAINS", TokenType::KW_CONTAINS),
CHECK_SEMANTIC_TYPE("Contains", TokenType::KW_CONTAINS),
CHECK_SEMANTIC_TYPE("contains", TokenType::KW_CONTAINS),
CHECK_SEMANTIC_TYPE("STARTS", TokenType::KW_STARTS),
CHECK_SEMANTIC_TYPE("Starts", TokenType::KW_STARTS),
CHECK_SEMANTIC_TYPE("starts", TokenType::KW_STARTS),
CHECK_SEMANTIC_TYPE("ENDS", TokenType::KW_ENDS),
CHECK_SEMANTIC_TYPE("Ends", TokenType::KW_ENDS),
CHECK_SEMANTIC_TYPE("ends", TokenType::KW_ENDS),
CHECK_SEMANTIC_TYPE("STARTS WITH", TokenType::KW_STARTS_WITH),
CHECK_SEMANTIC_TYPE("Starts with", TokenType::KW_STARTS_WITH),
CHECK_SEMANTIC_TYPE("starts with", TokenType::KW_STARTS_WITH),
......
......@@ -110,7 +110,7 @@ if __name__ == "__main__":
# Switch to your $src_dir/tests
os.chdir(TEST_DIR)
error_code = executor.run_tests(args)
# data_loader.drop_data()
data_loader.drop_data()
except Exception as x:
print('\033[31m' + str(x) + '\033[0m')
......
......@@ -1418,6 +1418,9 @@ class TestGoQuery(NebulaTestSuite):
self.check_resp_succeeded(resp)
self.check_empty_result(resp)
# todo: add test for NOT_CONTAINS
# def test_not_contains(self):
def test_with_intermediate_data(self):
# zero to zero
stmt = "GO 0 TO 0 STEPS FROM 'Tony Parker' OVER like YIELD DISTINCT like._dst"
......
......@@ -23,11 +23,12 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"column_names" : ['(apple STARTS WITH app)'],
"rows" : [
[True]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' STARTS WITH 'a'"
......@@ -35,11 +36,12 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"column_names" : ['(apple STARTS WITH a)'],
"rows" : [
[True]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' STARTS WITH 'A'"
......@@ -47,11 +49,12 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"column_names" : ['(apple STARTS WITH A)'],
"rows" : [
[False]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' STARTS WITH 'b'"
......@@ -59,16 +62,70 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"column_names" : ['(apple STARTS WITH b)'],
"rows" : [
[False]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD '123' STARTS WITH '1'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
# expected column names should contain "" or '' if the query contains a string
# to fix this issue, update toString() method in modules/common/src/common/datatypes/Value.cpp
# the fix could causes past tests fail
expected_data = {
"column_names" : ['(123 STARTS WITH 1)'],
"rows" : [
[True]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 123 STARTS WITH 1"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['(123 STARTS WITH 1)'],
"rows" : [
[T_NULL_BAD_TYPE]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
def test_not_starts_with(self):
stmt = "YIELD 'apple' NOT STARTS WITH 'app'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[False]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' NOT STARTS WITH 'a'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[False]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' NOT STARTS WITH 'A'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
......@@ -78,7 +135,31 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 123 STARTS WITH 1"
stmt = "YIELD 'apple' NOT STARTS WITH 'b'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[True]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD '123' NOT STARTS WITH '1'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[False]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 123 NOT STARTS WITH 1"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
......@@ -90,16 +171,17 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
}
self.check_out_of_order_result(resp, expected_data["rows"])
@pytest.mark.skip(reason="query result was auto-deduped")
def test_starts_with_GO(self):
stmt = '''GO FROM 'Tony Parker' OVER like WHERE like.likeness IN [95,56,21]
AND $$.player.name starts with 'Tim' YIELD $$.player.name '''
stmt = '''GO FROM 'Tony Parker' OVER like WHERE $^.player.name STARTS WITH 'Tony' YIELD $^.player.name'''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$$.player.name'],
"column_names" : ['$^.player.name'],
"rows" : [
['Tim Duncan'],
['Tony Parker'],
['Tony Parker']
]
}
self.check_column_names(resp, expected_data["column_names"])
......@@ -145,6 +227,68 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
def test_not_starts_with_GO(self):
stmt = '''GO FROM 'Tony Parker' OVER like WHERE like._dst NOT STARTS WITH 'T' YIELD $^.player.name'''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$^.player.name'],
"rows" : [
['Tony Parker'],
['Tony Parker'],
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = '''$A = GO FROM 'Tony Parker' OVER like YIELD like._dst AS ID;
GO FROM $A.ID OVER like WHERE like.likeness NOT IN [95,56,21]
AND $$.player.name NOT STARTS WITH 'Tony' YIELD $^.player.name, $$.player.name, like.likeness'''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$^.player.name', '$$.player.name', 'like.likeness'],
"rows" : [
['Manu Ginobili', 'Tim Duncan', 90],
['LaMarcus Aldridge', 'Tim Duncan', 75],
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = '''$A = GO FROM 'Tony Parker' OVER like YIELD like._dst AS ID;
GO FROM $A.ID OVER like WHERE like.likeness NOT IN [95,56,21]
AND $^.player.name NOT STARTS WITH 'LaMarcus' YIELD $^.player.name, $$.player.name, like.likeness'''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$^.player.name', '$$.player.name', 'like.likeness'],
"rows" : [
['Manu Ginobili', 'Tim Duncan', 90],
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = '''$A = GO FROM 'Tony Parker' OVER like YIELD like._dst AS ID;
GO FROM $A.ID OVER like WHERE like.likeness NOT IN [95,56,21]
AND $$.player.name NOT STARTS WITH 'Tony' YIELD $^.player.name, $$.player.name, like.likeness'''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$^.player.name', '$$.player.name', 'like.likeness'],
"rows" : [
['Manu Ginobili', 'Tim Duncan', 90],
['LaMarcus Aldridge', 'Tim Duncan', 75],
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
def test_ends_with(self):
stmt = "YIELD 'apple' ENDS WITH 'le'"
......@@ -241,59 +385,131 @@ class TestStartsWithAndEndsWith(NebulaTestSuite):
[T_NULL_BAD_TYPE]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
self.check_out_of_order_result(resp, expected_data["rows"])
def test_ends_with_GO(self):
stmt = '''GO FROM 'Tony Parker' OVER like WHERE like.likeness IN [95,56,21]
AND $$.player.name ENDS WITH 'can' YIELD $$.player.name '''
def test_not_ends_with(self):
stmt = "YIELD 'apple' NOT ENDS WITH 'le'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$$.player.name'],
"column_names" : [],
"rows" : [
['Tim Duncan'],
[False]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = '''GO FROM 'Tony Parker' OVER like WHERE like._dst IN ['Tim Duncan', 'Danny Green']
AND $$.player.name ENDS WITH 'Smith' YIELD $$.player.name'''
stmt = "YIELD 'apple' NOT ENDS WITH 'app'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$$.player.name'],
"column_names" : [],
"rows" : [
[True]
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = '''$A = GO FROM 'Tony Parker' OVER like YIELD like._dst AS ID;
GO FROM $A.ID OVER like WHERE like.likeness NOT IN [95,56,21]
AND $$.player.name ENDS WITH 'PARKER' YIELD $^.player.name, $$.player.name, like.likeness'''
stmt = "YIELD 'apple' NOT ENDS WITH 'a'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$^.player.name', '$$.player.name', 'like.likeness'],
"column_names" : [],
"rows" : [
[True]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' NOT ENDS WITH 'e'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[False]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' NOT ENDS WITH 'E'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[True]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 'apple' NOT ENDS WITH 'b'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[True]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD '123' NOT ENDS WITH '3'"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[False]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = "YIELD 123 NOT ENDS WITH 3"
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : [],
"rows" : [
[T_NULL_BAD_TYPE]
]
}
self.check_out_of_order_result(resp, expected_data["rows"])
@pytest.mark.skip(reason="storage issue caused this test fail link: https://github.com/vesoft-inc/nebula-storage/issues/166")
def test_ends_with_GO(self):
stmt = '''GO FROM 'Tony Parker' OVER like WHERE like._dst ENDS WITH 'Ginobili' YIELD $^.player.name '''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
# print(resp)
expected_data = {
"column_names" : ['$^.player.name'],
"rows" : [
['Tony Parker'],
]
}
self.check_column_names(resp, expected_data["column_names"])
self.check_out_of_order_result(resp, expected_data["rows"])
stmt = '''$A = GO FROM 'Tony Parker' OVER like YIELD like._dst AS ID;
GO FROM $A.ID OVER like WHERE like.likeness NOT IN [95,56,21]
AND $$.player.name ENDS WITH 'Parker' YIELD $^.player.name, $$.player.name, like.likeness'''
@pytest.mark.skip(reason="storage issue caused this test fail link: https://github.com/vesoft-inc/nebula-storage/issues/166")
def test_not_ends_with_GO(self):
stmt = '''GO FROM 'Tony Parker' OVER like WHERE like._dst NOT ENDS WITH 'Ginobili' YIELD $^.player.name '''
resp = self.execute_query(stmt)
self.check_resp_succeeded(resp)
expected_data = {
"column_names" : ['$^.player.name', '$$.player.name', 'like.likeness'],
"column_names" : ['$^.player.name'],
"rows" : [
['LaMarcus Aldridge', 'Tony Parker', 75],
['Tony Parker'],
['Tony Parker'],
]
}
self.check_column_names(resp, expected_data["column_names"])
......
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