diff --git a/src/parser/parser.yy b/src/parser/parser.yy index ad0d856f729db5b5988a0f1f2b7bc2451ec877df..985199ea6569f3f09eb12c2f136645f452bd36a1 100644 --- a/src/parser/parser.yy +++ b/src/parser/parser.yy @@ -23,6 +23,7 @@ #include "common/expression/VariableExpression.h" #include "common/expression/CaseExpression.h" #include "common/expression/TextSearchExpression.h" +#include "common/expression/PredicateExpression.h" #include "common/expression/ListComprehensionExpression.h" #include "common/expression/AggregateExpression.h" @@ -182,6 +183,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL; %token KW_LISTENER KW_ELASTICSEARCH %token KW_AUTO KW_FUZZY KW_PREFIX KW_REGEXP KW_WILDCARD %token KW_TEXT KW_SEARCH KW_CLIENTS KW_SIGN KW_SERVICE KW_TEXT_SEARCH +%token KW_ANY KW_SINGLE KW_NONE /* symbols */ %token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE COMMA @@ -195,7 +197,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL; %token <doubleval> DOUBLE %token <strval> STRING VARIABLE LABEL IPV4 -%type <strval> name_label unreserved_keyword agg_function +%type <strval> name_label unreserved_keyword agg_function predicate_name %type <expr> expression %type <expr> property_expression %type <expr> vertex_prop_expression @@ -215,6 +217,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL; %type <expr> subscript_expression %type <expr> attribute_expression %type <expr> case_expression +%type <expr> predicate_expression %type <expr> list_comprehension_expression %type <expr> compound_expression %type <expr> aggregate_expression @@ -453,6 +456,9 @@ unreserved_keyword | KW_META { $$ = new std::string("meta"); } | KW_STORAGE { $$ = new std::string("storage"); } | KW_ALL { $$ = new std::string("all"); } + | KW_ANY { $$ = new std::string("any"); } + | KW_SINGLE { $$ = new std::string("single"); } + | KW_NONE { $$ = new std::string("none"); } | KW_SHORTEST { $$ = new std::string("shortest"); } | KW_NOLOOP { $$ = new std::string("noloop"); } | KW_COUNT_DISTINCT { $$ = new std::string("count_distinct"); } @@ -627,6 +633,9 @@ expression | case_expression { $$ = $1; } + | predicate_expression { + $$ = $1; + } | list_comprehension_expression { $$ = $1; } @@ -749,6 +758,24 @@ when_then_list } ; +predicate_name + : KW_ALL { $$ = new std::string("all"); } + | KW_ANY { $$ = new std::string("any"); } + | KW_SINGLE { $$ = new std::string("single"); } + | KW_NONE { $$ = new std::string("none"); } + ; + +predicate_expression + : predicate_name L_PAREN expression KW_IN expression KW_WHERE expression R_PAREN { + if ($3->kind() != Expression::Kind::kLabel) { + throw nebula::GraphParser::syntax_error(@3, "The loop variable must be a label in predicate functions"); + } + auto &innerVar = *(static_cast<const LabelExpression *>($3)->name()); + auto *expr = new PredicateExpression($1, new std::string(innerVar), $5, $7); + nebula::graph::ParserUtil::rewritePred(qctx, expr, innerVar); + $$ = expr; + delete $3; + } list_comprehension_expression : L_BRACKET expression KW_IN expression KW_WHERE expression R_BRACKET { diff --git a/src/parser/scanner.lex b/src/parser/scanner.lex index bb9a31d9eb9cc7cffaac97c132ee07779602a386..d3e1696c3da25700b2761f8dbd9a4cd3b9eae578 100644 --- a/src/parser/scanner.lex +++ b/src/parser/scanner.lex @@ -166,6 +166,9 @@ IP_OCTET ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) "COLLATION" { return TokenType::KW_COLLATION; } "ATOMIC_EDGE" { return TokenType::KW_ATOMIC_EDGE; } "ALL" { return TokenType::KW_ALL; } +"ANY" { return TokenType::KW_ANY; } +"SINGLE" { return TokenType::KW_SINGLE; } +"NONE" { return TokenType::KW_NONE; } "LEADER" { return TokenType::KW_LEADER; } "UUID" { return TokenType::KW_UUID; } "DATA" { return TokenType::KW_DATA; } diff --git a/src/parser/test/ScannerTest.cpp b/src/parser/test/ScannerTest.cpp index 710e18209705a1c94741157bf45e28f542746253..917c7b5e50e0b26ccd98b2b0cb322679eaa37932 100644 --- a/src/parser/test/ScannerTest.cpp +++ b/src/parser/test/ScannerTest.cpp @@ -482,6 +482,12 @@ TEST(Scanner, Basic) { CHECK_SEMANTIC_TYPE("STATS", TokenType::KW_STATS), CHECK_SEMANTIC_TYPE("Stats", TokenType::KW_STATS), CHECK_SEMANTIC_TYPE("stats", TokenType::KW_STATS), + CHECK_SEMANTIC_TYPE("ANY", TokenType::KW_ANY), + CHECK_SEMANTIC_TYPE("any", TokenType::KW_ANY), + CHECK_SEMANTIC_TYPE("SINGLE", TokenType::KW_SINGLE), + CHECK_SEMANTIC_TYPE("single", TokenType::KW_SINGLE), + CHECK_SEMANTIC_TYPE("NONE", TokenType::KW_NONE), + CHECK_SEMANTIC_TYPE("none", TokenType::KW_NONE), CHECK_SEMANTIC_TYPE("CASE", TokenType::KW_CASE), CHECK_SEMANTIC_TYPE("case", TokenType::KW_CASE), CHECK_SEMANTIC_TYPE("WHEN", TokenType::KW_WHEN), @@ -521,8 +527,8 @@ TEST(Scanner, Basic) { CHECK_SEMANTIC_VALUE("0x7FFFFFFFFFFFFFFF", TokenType::INTEGER, 0x7FFFFFFFFFFFFFFFL), CHECK_SEMANTIC_VALUE("0x007FFFFFFFFFFFFFFF", TokenType::INTEGER, 0x007FFFFFFFFFFFFFFFL), CHECK_SEMANTIC_VALUE("9223372036854775807", TokenType::INTEGER, 9223372036854775807L), - CHECK_SEMANTIC_VALUE("00777777777777777777777", TokenType::INTEGER, - 00777777777777777777777), + CHECK_SEMANTIC_VALUE( + "00777777777777777777777", TokenType::INTEGER, 00777777777777777777777), CHECK_LEXICAL_ERROR("9223372036854775809"), CHECK_LEXICAL_ERROR("0x8000000000000001"), CHECK_LEXICAL_ERROR("001000000000000000000001"), @@ -558,7 +564,6 @@ TEST(Scanner, Basic) { CHECK_SEMANTIC_VALUE("\"\\\\\\\\110 \"", TokenType::STRING, "\\\\110 "), CHECK_SEMANTIC_VALUE("\"\\\\\\\\\110 \"", TokenType::STRING, "\\\\H "), - CHECK_SEMANTIC_VALUE("\"宸辨墍涓嶆锛屽嬁鏂戒簬浜篭"", TokenType::STRING, "宸辨墍涓嶆锛屽嬁鏂戒簬浜�"), }; #undef CHECK_SEMANTIC_TYPE diff --git a/src/util/ParserUtil.h b/src/util/ParserUtil.h index 7c2c968b09b58745ec7c38634ebbd6dbf895378c..2301876315fb5841a3def45f5796c91d70b228f5 100644 --- a/src/util/ParserUtil.h +++ b/src/util/ParserUtil.h @@ -81,6 +81,50 @@ public: lc->setMapping(newMapping); } } + + static void rewritePred(QueryContext *qctx, + PredicateExpression *pred, + const std::string &oldVarName) { + const auto &newVarName = qctx->vctx()->anonVarGen()->getVar(); + qctx->ectx()->setValue(newVarName, Value()); + auto rewriter = [&oldVarName, &newVarName](const Expression *expr) { + Expression *ret = nullptr; + if (expr->kind() == Expression::Kind::kLabel) { + auto *label = static_cast<const LabelExpression *>(expr); + if (*label->name() == oldVarName) { + ret = new VariableExpression(new std::string(newVarName)); + } else { + ret = label->clone().release(); + } + } else { + DCHECK(expr->kind() == Expression::Kind::kLabelAttribute); + auto *la = static_cast<const LabelAttributeExpression *>(expr); + if (*la->left()->name() == oldVarName) { + const auto &value = la->right()->value(); + ret = + new AttributeExpression(new VariableExpression(new std::string(newVarName)), + new ConstantExpression(value)); + } else { + ret = la->clone().release(); + } + } + return ret; + }; + + RewriteMatchLabelVisitor visitor(rewriter); + + pred->setOriginString(new std::string(pred->makeString())); + pred->setInnerVar(new std::string(newVarName)); + Expression *filter = pred->filter(); + Expression *newFilter = nullptr; + if (isLabel(filter)) { + newFilter = rewriter(filter); + } else { + newFilter = filter->clone().release(); + newFilter->accept(&visitor); + } + pred->setFilter(newFilter); + } }; } // namespace graph diff --git a/src/visitor/CollectAllExprsVisitor.cpp b/src/visitor/CollectAllExprsVisitor.cpp index e1599c1e064b59f5f08886ea9f548be7becd3d37..172f37a978c089bcde2b6fa5f162ad35b68e541c 100644 --- a/src/visitor/CollectAllExprsVisitor.cpp +++ b/src/visitor/CollectAllExprsVisitor.cpp @@ -157,6 +157,12 @@ void CollectAllExprsVisitor::visit(ListComprehensionExpression* expr) { } } +void CollectAllExprsVisitor::visit(PredicateExpression *expr) { + collectExpr(expr); + expr->collection()->accept(this); + expr->filter()->accept(this); +} + void CollectAllExprsVisitor::visitBinaryExpr(BinaryExpression *expr) { collectExpr(expr); expr->left()->accept(this); diff --git a/src/visitor/CollectAllExprsVisitor.h b/src/visitor/CollectAllExprsVisitor.h index fa6b16c25490bda6b9386f6592cc0badf0d3c264..d421a9cf0acbbdbf766f7258ed1dd8f9bd2a4221 100644 --- a/src/visitor/CollectAllExprsVisitor.h +++ b/src/visitor/CollectAllExprsVisitor.h @@ -56,6 +56,7 @@ private: void visit(VertexExpression* expr) override; void visit(EdgeExpression* expr) override; void visit(CaseExpression* expr) override; + void visit(PredicateExpression* expr) override; void visit(ListComprehensionExpression* expr) override; void visit(ColumnExpression* expr) override; diff --git a/src/visitor/DeduceTypeVisitor.cpp b/src/visitor/DeduceTypeVisitor.cpp index 1bc42b21e942f86acdb26ed2620ac992e47b2ee1..2e77d4716591ed934378f3eff0f4aa6b1593be85 100644 --- a/src/visitor/DeduceTypeVisitor.cpp +++ b/src/visitor/DeduceTypeVisitor.cpp @@ -601,6 +601,25 @@ void DeduceTypeVisitor::visit(CaseExpression *expr) { type_ = Value::Type::__EMPTY__; } +void DeduceTypeVisitor::visit(PredicateExpression *expr) { + expr->collection()->accept(this); + if (!ok()) return; + if (type_ == Value::Type::NULLVALUE || type_ == Value::Type::__EMPTY__) { + return; + } + if (type_ != Value::Type::LIST) { + std::stringstream ss; + ss << "`" << expr->toString().c_str() + << "': Invalid colletion type, expected type of LIST, but was:" << type_; + status_ = Status::SemanticError(ss.str()); + return; + } + expr->filter()->accept(this); + if (!ok()) return; + + type_ = Value::Type::BOOL; +} + void DeduceTypeVisitor::visit(ListComprehensionExpression *expr) { expr->collection()->accept(this); if (!ok()) { diff --git a/src/visitor/DeduceTypeVisitor.h b/src/visitor/DeduceTypeVisitor.h index fe3e0a9a34bac539cf4014af5b8e104b9fe6d488..a21de5c21a042d3553b3560981757f721fa92763 100644 --- a/src/visitor/DeduceTypeVisitor.h +++ b/src/visitor/DeduceTypeVisitor.h @@ -84,6 +84,8 @@ private: void visit(PathBuildExpression *expr) override; // column expression void visit(ColumnExpression * expr) override; + // predicate expression + void visit(PredicateExpression *expr) override; // list comprehension expression void visit(ListComprehensionExpression *) override; diff --git a/src/visitor/ExprVisitorImpl.cpp b/src/visitor/ExprVisitorImpl.cpp index 9f549e99fdfd71eceedd08fec2f12f6503ebd668..0835f769b607bb3fa168611c1dba7a7def7453cf 100644 --- a/src/visitor/ExprVisitorImpl.cpp +++ b/src/visitor/ExprVisitorImpl.cpp @@ -145,6 +145,14 @@ void ExprVisitorImpl::visit(PathBuildExpression *expr) { } } +void ExprVisitorImpl::visit(PredicateExpression *expr) { + DCHECK(ok()); + expr->collection()->accept(this); + if (!ok()) return; + expr->filter()->accept(this); + if (!ok()) return; +} + void ExprVisitorImpl::visit(ListComprehensionExpression *expr) { DCHECK(ok()); expr->collection()->accept(this); diff --git a/src/visitor/ExprVisitorImpl.h b/src/visitor/ExprVisitorImpl.h index 2f24b5d7aad75363834b5a5ebfbb064a18629c79..9660a859ec01056ff1c75ac7994fab57fc503bab 100644 --- a/src/visitor/ExprVisitorImpl.h +++ b/src/visitor/ExprVisitorImpl.h @@ -34,6 +34,8 @@ public: void visit(CaseExpression *expr) override; // path build expression void visit(PathBuildExpression *expr) override; + // predicate expression + void visit(PredicateExpression *expr) override; // list comprehension expression void visit(ListComprehensionExpression *expr) override; diff --git a/src/visitor/FindAnyExprVisitor.cpp b/src/visitor/FindAnyExprVisitor.cpp index 6b85c5d618bbbfef7ba807cfa98c001d525410a9..9286e09989d90129fbe786b75fbd3b3c32a09340 100644 --- a/src/visitor/FindAnyExprVisitor.cpp +++ b/src/visitor/FindAnyExprVisitor.cpp @@ -87,6 +87,15 @@ void FindAnyExprVisitor::visit(CaseExpression *expr) { } } +void FindAnyExprVisitor::visit(PredicateExpression *expr) { + findExpr(expr); + if (found_) return; + expr->collection()->accept(this); + if (found_) return; + expr->filter()->accept(this); + if (found_) return; +} + void FindAnyExprVisitor::visit(ConstantExpression *expr) { findExpr(expr); } diff --git a/src/visitor/FindAnyExprVisitor.h b/src/visitor/FindAnyExprVisitor.h index fb53103b03cabb4f91e2d81476ffec89dbacf8b7..fafb7b3ad5cd066fdbf03818b704ffa87b47097a 100644 --- a/src/visitor/FindAnyExprVisitor.h +++ b/src/visitor/FindAnyExprVisitor.h @@ -39,6 +39,7 @@ private: void visit(SetExpression* expr) override; void visit(MapExpression* expr) override; void visit(CaseExpression* expr) override; + void visit(PredicateExpression* expr) override; void visit(ConstantExpression* expr) override; void visit(EdgePropertyExpression* expr) override; diff --git a/src/visitor/FoldConstantExprVisitor.cpp b/src/visitor/FoldConstantExprVisitor.cpp index a8abe6ac06ea18d434b023b10b5c8387fca5408f..7949b31860f6b15b9c6d11c374d3aab2f57655a8 100644 --- a/src/visitor/FoldConstantExprVisitor.cpp +++ b/src/visitor/FoldConstantExprVisitor.cpp @@ -381,5 +381,26 @@ void FoldConstantExprVisitor::visit(ListComprehensionExpression *expr) { canBeFolded_ = canBeFolded; } +void FoldConstantExprVisitor::visit(PredicateExpression *expr) { + bool canBeFolded = true; + if (!isConstant(expr->collection())) { + expr->collection()->accept(this); + if (canBeFolded_) { + expr->setCollection(fold(expr->collection())); + } else { + canBeFolded = false; + } + } + if (!isConstant(expr->filter())) { + expr->filter()->accept(this); + if (canBeFolded_) { + expr->setFilter(fold(expr->filter())); + } else { + canBeFolded = false; + } + } + canBeFolded_ = canBeFolded; +} + } // namespace graph } // namespace nebula diff --git a/src/visitor/FoldConstantExprVisitor.h b/src/visitor/FoldConstantExprVisitor.h index 18995604ebcfb659f67c269155595cd128e996a7..532c864ef99c68d15a21594324e3035036fa0789 100644 --- a/src/visitor/FoldConstantExprVisitor.h +++ b/src/visitor/FoldConstantExprVisitor.h @@ -64,6 +64,8 @@ public: void visit(PathBuildExpression *expr) override; // column expression void visit(ColumnExpression *expr) override; + // predicate expression + void visit(PredicateExpression *expr) override; // list comprehension expression void visit(ListComprehensionExpression *) override; diff --git a/src/visitor/RewriteInputPropVisitor.cpp b/src/visitor/RewriteInputPropVisitor.cpp index b93635ca7dee09e790417bc523d27aba6d054c56..db4bab96f96922752a0378b7c7fa637e8052bf40 100644 --- a/src/visitor/RewriteInputPropVisitor.cpp +++ b/src/visitor/RewriteInputPropVisitor.cpp @@ -271,5 +271,17 @@ void RewriteInputPropVisitor::visit(PathBuildExpression* expr) { } } } + +void RewriteInputPropVisitor::visit(PredicateExpression* expr) { + expr->collection()->accept(this); + if (ok()) { + expr->setCollection(result_.release()); + } + expr->filter()->accept(this); + if (ok()) { + expr->setFilter(result_.release()); + } +} + } // namespace graph } // namespace nebula diff --git a/src/visitor/RewriteInputPropVisitor.h b/src/visitor/RewriteInputPropVisitor.h index a15a94797ebf9fabdedf1733fc83e2c8924a0513..8f649c8d930d59d1f958ecf8bbf7673258e5d520 100644 --- a/src/visitor/RewriteInputPropVisitor.h +++ b/src/visitor/RewriteInputPropVisitor.h @@ -76,6 +76,8 @@ private: void visit(PathBuildExpression *expr) override; // column expression void visit(ColumnExpression* expr) override; + // predicate expression + void visit(PredicateExpression *) override; // list comprehension expression void visit(ListComprehensionExpression *) override; diff --git a/src/visitor/RewriteLabelAttrVisitor.cpp b/src/visitor/RewriteLabelAttrVisitor.cpp index e44cf2c290f79bf37ec3a3d5fa1017806fa93045..5719d67869f5f59520c706b45ae043d11babcd46 100644 --- a/src/visitor/RewriteLabelAttrVisitor.cpp +++ b/src/visitor/RewriteLabelAttrVisitor.cpp @@ -145,6 +145,21 @@ void RewriteLabelAttrVisitor::visit(ListComprehensionExpression* expr) { } } +void RewriteLabelAttrVisitor::visit(PredicateExpression* expr) { + if (isLabelAttrExpr(expr->collection())) { + auto newExpr = static_cast<LabelAttributeExpression*>(expr->collection()); + expr->setCollection(createExpr(newExpr)); + } else { + expr->collection()->accept(this); + } + if (isLabelAttrExpr(expr->filter())) { + auto newExpr = static_cast<LabelAttributeExpression*>(expr->filter()); + expr->setFilter(createExpr(newExpr)); + } else { + expr->filter()->accept(this); + } +} + void RewriteLabelAttrVisitor::visitBinaryExpr(BinaryExpression* expr) { if (isLabelAttrExpr(expr->left())) { auto left = static_cast<const LabelAttributeExpression*>(expr->left()); diff --git a/src/visitor/RewriteLabelAttrVisitor.h b/src/visitor/RewriteLabelAttrVisitor.h index 2ca5030348130bf0725ec242a27af7d7863afbbd..6ac46e6dd5d78b3e6d3d14bbfc15367429b87f4a 100644 --- a/src/visitor/RewriteLabelAttrVisitor.h +++ b/src/visitor/RewriteLabelAttrVisitor.h @@ -33,6 +33,7 @@ private: void visit(SetExpression *expr) override; void visit(MapExpression *expr) override; void visit(CaseExpression *) override; + void visit(PredicateExpression *) override; void visit(ListComprehensionExpression *) override; void visit(ConstantExpression *) override {} void visit(LabelExpression *) override {} diff --git a/src/visitor/RewriteMatchLabelVisitor.cpp b/src/visitor/RewriteMatchLabelVisitor.cpp index 3782f177961b7da3bd025504c95c490a7f08e9d9..a0d24c1867a7e0aa8fda2065de75f23c6dc634a6 100644 --- a/src/visitor/RewriteMatchLabelVisitor.cpp +++ b/src/visitor/RewriteMatchLabelVisitor.cpp @@ -143,6 +143,19 @@ void RewriteMatchLabelVisitor::visit(ListComprehensionExpression *expr) { } } +void RewriteMatchLabelVisitor::visit(PredicateExpression *expr) { + if (isLabel(expr->collection())) { + expr->setCollection(rewriter_(expr)); + } else { + expr->collection()->accept(this); + } + if (isLabel(expr->filter())) { + expr->setFilter(rewriter_(expr)); + } else { + expr->filter()->accept(this); + } +} + void RewriteMatchLabelVisitor::visitBinaryExpr(BinaryExpression *expr) { if (isLabel(expr->left())) { expr->setLeft(rewriter_(expr->left())); diff --git a/src/visitor/RewriteMatchLabelVisitor.h b/src/visitor/RewriteMatchLabelVisitor.h index 1775c05b9f7b8428a8862e7dd6c432fec00a59e6..0b57d26a9b834e1b45c78c2f1f8201fe66dc5644 100644 --- a/src/visitor/RewriteMatchLabelVisitor.h +++ b/src/visitor/RewriteMatchLabelVisitor.h @@ -60,6 +60,7 @@ private: void visit(VertexExpression*) override {} void visit(EdgeExpression*) override {} void visit(ColumnExpression*) override {} + void visit(PredicateExpression *) override; void visit(ListComprehensionExpression*) override; void visitBinaryExpr(BinaryExpression *) override; diff --git a/src/visitor/RewriteSymExprVisitor.cpp b/src/visitor/RewriteSymExprVisitor.cpp index 892c1fd5908f381db5ae8029b0b925383f6cc4f3..345c62fb51b05401c5c8bebcd83a6ad7e84f6bee 100644 --- a/src/visitor/RewriteSymExprVisitor.cpp +++ b/src/visitor/RewriteSymExprVisitor.cpp @@ -287,5 +287,16 @@ void RewriteSymExprVisitor::visit(ListComprehensionExpression *expr) { } } +void RewriteSymExprVisitor::visit(PredicateExpression *expr) { + expr->collection()->accept(this); + if (expr_) { + expr->setCollection(expr_.release()); + } + expr->filter()->accept(this); + if (expr_) { + expr->setFilter(expr_.release()); + } +} + } // namespace graph } // namespace nebula diff --git a/src/visitor/RewriteSymExprVisitor.h b/src/visitor/RewriteSymExprVisitor.h index 6e14c56fa589c9da5f7f147dcc7173c04868ef97..76c2ef73f0aee9083a1d9b9a38f3bae9200808e0 100644 --- a/src/visitor/RewriteSymExprVisitor.h +++ b/src/visitor/RewriteSymExprVisitor.h @@ -71,6 +71,8 @@ public: void visit(PathBuildExpression *expr) override; // column expression void visit(ColumnExpression *expr) override; + // predicate expression + void visit(PredicateExpression *expr) override; // list comprehension expression void visit(ListComprehensionExpression *expr) override; diff --git a/tests/tck/features/expression/predicate.feature b/tests/tck/features/expression/predicate.feature new file mode 100644 index 0000000000000000000000000000000000000000..836a511679c7deb675eef31a889ff56d6a49f4f0 --- /dev/null +++ b/tests/tck/features/expression/predicate.feature @@ -0,0 +1,76 @@ +# Copyright (c) 2020 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. +@jie +Feature: Predicate + + Scenario: yield a predicate + Given a graph with space named "nba" + When executing query: + """ + YIELD all(n IN range(1, 5) WHERE n > 2) AS r + """ + Then the result should be, in any order: + | r | + | False | + When executing query: + """ + YIELD any(n IN [1, 2, 3, 4, 5] WHERE n > 2) AS r + """ + Then the result should be, in any order: + | r | + | True | + When executing query: + """ + YIELD single(n IN range(1, 5) WHERE n == 3) AS r + """ + Then the result should be, in any order: + | r | + | True | + When executing query: + """ + YIELD none(n IN range(1, 3) WHERE n == 0) AS r + """ + Then the result should be, in any order: + | r | + | True | + + Scenario: use a predicate in GO + Given a graph with space named "nba" + When executing query: + """ + GO FROM "Tony Parker" OVER like + WHERE any(x IN [5, 10] WHERE like.likeness + $$.player.age + x > 100) + YIELD like._dst AS id, like.likeness AS likeness + """ + Then the result should be, in any order: + | id | likeness | + | "LaMarcus Aldridge" | 90 | + | "Manu Ginobili" | 95 | + | "Tim Duncan" | 95 | + + Scenario: use a predicate in MATCH + Given a graph with space named "nba" + When executing query: + """ + MATCH p = (n:player{name:"LeBron James"})<-[:like]-(m) + RETURN nodes(p)[0].name AS n1, nodes(p)[1].name AS n2, + all(n IN nodes(p) WHERE n.name NOT STARTS WITH "D") AS b + """ + Then the result should be, in any order: + | n1 | n2 | b | + | "LeBron James" | "Carmelo Anthony" | True | + | "LeBron James" | "Chris Paul" | True | + | "LeBron James" | "Danny Green" | False | + | "LeBron James" | "Dejounte Murray" | False | + | "LeBron James" | "Dwyane Wade" | False | + | "LeBron James" | "Kyrie Irving" | True | + When executing query: + """ + MATCH p = (n:player{name:"LeBron James"})-[:like]->(m) + RETURN single(n IN nodes(p) WHERE n.age > 40) as b + """ + Then the result should be, in any order: + | b | + | True |