From 2c769adfb5a7b9f0974d6dfe7667931f1df61c1d Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 11 Jun 2024 21:09:09 +0800 Subject: [PATCH] implemented the integration of cypher into the GQL ASTNode system, and fixed bugs in the GQL match feature (#533) * add cypher test compare result * implement query * implement match query * implement standalone call and create * cpplint * cpplint * cpplint * fix double format * update * update * implement set * implement gql set * fix test case * move dml * cpplint * cpplint * remove ddl header * fix compile error * follow comment * comments * comments * comments * cpplint * comments * comments * comments * comments * comments * fix bug * fix bug * remove incorrect comments * fix bug * comments --------- Co-authored-by: Shipeng Qi Co-authored-by: Ke Huang <569078986@qq.com> --- .../include/geax-front-end/ast/AstDumper.h | 9 + .../include/geax-front-end/ast/AstNode.h | 1 + .../geax-front-end/ast/AstNodeVisitor.h | 6 + .../include/geax-front-end/ast/expr/BSquare.h | 34 + .../geax-front-end/ast/expr/ExprNodeFwd.h | 1 + src/BuildCypherLib.cmake | 3 + .../arithmetic/arithmetic_expression.cpp | 56 +- src/cypher/arithmetic/arithmetic_expression.h | 21 + src/cypher/arithmetic/ast_expr_evaluator.cpp | 69 +- src/cypher/arithmetic/ast_expr_evaluator.h | 19 +- .../execution_plan/clause_read_only_decider.h | 49 + .../execution_plan/execution_plan_maker.cpp | 152 +- .../execution_plan/execution_plan_maker.h | 13 +- .../execution_plan/execution_plan_v2.cpp | 7 +- src/cypher/execution_plan/execution_plan_v2.h | 3 + src/cypher/execution_plan/ops/op.h | 2 +- .../ops/op_gql_standalone_call.cpp | 96 + .../ops/op_gql_standalone_call.h | 63 + src/cypher/execution_plan/ops/ops.h | 1 + .../execution_plan/pattern_graph_maker.cpp | 127 +- .../execution_plan/pattern_graph_maker.h | 3 + src/cypher/parser/cypher_base_visitor_v2.cpp | 1701 ++++++++++ src/cypher/parser/cypher_base_visitor_v2.h | 318 ++ src/cypher/procedure/procedure_v2.cpp | 2984 +++++++++++++++++ src/cypher/procedure/procedure_v2.h | 1042 ++++++ src/cypher/utils/ast_node_visitor_impl.h | 6 + src/cypher/utils/geax_expr_util.h | 15 +- src/cypher/utils/geax_util.h | 8 + test/CMakeLists.txt | 1 + test/resource/unit_test/add/cypher/add.result | 26 + test/resource/unit_test/add/cypher/add.test | 13 + .../aggregate/cypher/aggregate.result | 40 + .../unit_test/aggregate/cypher/aggregate.test | 20 + .../unit_test/algo/cypher/algo.result | 18 + test/resource/unit_test/algo/cypher/algo.test | 9 + .../create_label/cypher/create_label.result | 20 + .../create_label/cypher/create_label.test | 10 + .../create_yago/cypher/create_yago.result | 21 + .../create_yago/cypher/create_yago.test | 10 + .../unit_test/delete/cypher/delete.result | 23 + .../unit_test/delete/cypher/delete.test | 12 + .../edge_id_query/cypher/edge_id_query.result | 24 + .../edge_id_query/cypher/edge_id_query.test | 12 + .../expression/cypher/expression.result | 256 ++ .../expression/cypher/expression.test | 128 + .../unit_test/find/cypher/find.result | 21 + test/resource/unit_test/find/cypher/find.test | 11 + .../cypher/fix_crash_issues.result | 84 + .../cypher/fix_crash_issues.test | 42 + .../func_filter/cypher/func_filter.result | 9 + .../func_filter/cypher/func_filter.test | 5 + .../unit_test/function/cypher/function.result | 93 + .../unit_test/function/cypher/function.test | 47 + .../unit_test/hint/cypher/hint.result | 9 + test/resource/unit_test/hint/cypher/hint.test | 5 + .../unit_test/ldbc_snb/cypher/ldbc_snb.result | 26 + .../unit_test/ldbc_snb/cypher/ldbc_snb.test | 13 + .../cypher/list_comprehension.result | 8 + .../cypher/list_comprehension.test | 4 + .../unit_test/merge/cypher/merge.result | 77 + .../unit_test/merge/cypher/merge.test | 39 + .../multi_match/cypher/multi_match.result | 9 + .../multi_match/cypher/multi_match.test | 5 + test/resource/unit_test/opt/cypher/opt.result | 73 + test/resource/unit_test/opt/cypher/opt.test | 37 + .../cypher/optional_match.result | 19 + .../optional_match/cypher/optional_match.test | 12 + .../unit_test/orderby/cypher/orderby.result | 35 + .../unit_test/orderby/cypher/orderby.test | 18 + .../unit_test/parameter/cypher/paratemer.test | 2 + .../procedure/cypher/procedure.result | 206 ++ .../unit_test/procedure/cypher/procedure.test | 107 + .../unit_test/profile/cypher/profile.result | 4 + .../unit_test/profile/cypher/profile.test | 2 + .../unit_test/query/cypher/query.result | 110 + .../unit_test/query/cypher/query.test | 55 + .../unit_test/remove/cypher/remove.result | 4 + .../unit_test/remove/cypher/remove.test | 2 + test/resource/unit_test/set/cypher/set.result | 39 + test/resource/unit_test/set/cypher/set.test | 20 + .../unit_test/topn/cypher/topn.result | 14 + test/resource/unit_test/topn/cypher/topn.test | 7 + .../undefined_var/cypher/undefined_var.result | 32 + .../undefined_var/cypher/undefined_var.test | 16 + .../unit_test/union/cypher/union.result | 6 + .../unit_test/union/cypher/union.test | 3 + .../uniqueness/cypher/uniqueness.result | 34 + .../uniqueness/cypher/uniqueness.test | 17 + .../unit_test/unwind/cypher/unwind.result | 63 + .../unit_test/unwind/cypher/unwind.test | 36 + .../var_len_edge/cypher/var_len_edge.result | 76 + .../var_len_edge/cypher/var_len_edge.test | 38 + .../unit_test/with/cypher/with.result | 86 + test/resource/unit_test/with/cypher/with.test | 47 + test/test_cypher_v2.cpp | 567 ++++ test/ut_types.h | 5 +- 96 files changed, 9691 insertions(+), 60 deletions(-) create mode 100644 deps/geax-front-end/include/geax-front-end/ast/expr/BSquare.h create mode 100644 src/cypher/execution_plan/clause_read_only_decider.h create mode 100644 src/cypher/execution_plan/ops/op_gql_standalone_call.cpp create mode 100644 src/cypher/execution_plan/ops/op_gql_standalone_call.h create mode 100644 src/cypher/parser/cypher_base_visitor_v2.cpp create mode 100644 src/cypher/parser/cypher_base_visitor_v2.h create mode 100644 src/cypher/procedure/procedure_v2.cpp create mode 100644 src/cypher/procedure/procedure_v2.h create mode 100644 test/resource/unit_test/add/cypher/add.result create mode 100644 test/resource/unit_test/add/cypher/add.test create mode 100644 test/resource/unit_test/aggregate/cypher/aggregate.result create mode 100644 test/resource/unit_test/aggregate/cypher/aggregate.test create mode 100644 test/resource/unit_test/algo/cypher/algo.result create mode 100644 test/resource/unit_test/algo/cypher/algo.test create mode 100644 test/resource/unit_test/create_label/cypher/create_label.result create mode 100644 test/resource/unit_test/create_label/cypher/create_label.test create mode 100644 test/resource/unit_test/create_yago/cypher/create_yago.result create mode 100644 test/resource/unit_test/create_yago/cypher/create_yago.test create mode 100644 test/resource/unit_test/delete/cypher/delete.result create mode 100644 test/resource/unit_test/delete/cypher/delete.test create mode 100644 test/resource/unit_test/edge_id_query/cypher/edge_id_query.result create mode 100644 test/resource/unit_test/edge_id_query/cypher/edge_id_query.test create mode 100644 test/resource/unit_test/expression/cypher/expression.result create mode 100644 test/resource/unit_test/expression/cypher/expression.test create mode 100644 test/resource/unit_test/find/cypher/find.result create mode 100644 test/resource/unit_test/find/cypher/find.test create mode 100644 test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.result create mode 100644 test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.test create mode 100644 test/resource/unit_test/func_filter/cypher/func_filter.result create mode 100644 test/resource/unit_test/func_filter/cypher/func_filter.test create mode 100644 test/resource/unit_test/function/cypher/function.result create mode 100644 test/resource/unit_test/function/cypher/function.test create mode 100644 test/resource/unit_test/hint/cypher/hint.result create mode 100644 test/resource/unit_test/hint/cypher/hint.test create mode 100644 test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.result create mode 100644 test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.test create mode 100644 test/resource/unit_test/list_comprehension/cypher/list_comprehension.result create mode 100644 test/resource/unit_test/list_comprehension/cypher/list_comprehension.test create mode 100644 test/resource/unit_test/merge/cypher/merge.result create mode 100644 test/resource/unit_test/merge/cypher/merge.test create mode 100644 test/resource/unit_test/multi_match/cypher/multi_match.result create mode 100644 test/resource/unit_test/multi_match/cypher/multi_match.test create mode 100644 test/resource/unit_test/opt/cypher/opt.result create mode 100644 test/resource/unit_test/opt/cypher/opt.test create mode 100644 test/resource/unit_test/optional_match/cypher/optional_match.result create mode 100644 test/resource/unit_test/optional_match/cypher/optional_match.test create mode 100644 test/resource/unit_test/orderby/cypher/orderby.result create mode 100644 test/resource/unit_test/orderby/cypher/orderby.test create mode 100644 test/resource/unit_test/parameter/cypher/paratemer.test create mode 100644 test/resource/unit_test/procedure/cypher/procedure.result create mode 100644 test/resource/unit_test/procedure/cypher/procedure.test create mode 100644 test/resource/unit_test/profile/cypher/profile.result create mode 100644 test/resource/unit_test/profile/cypher/profile.test create mode 100644 test/resource/unit_test/query/cypher/query.result create mode 100644 test/resource/unit_test/query/cypher/query.test create mode 100644 test/resource/unit_test/remove/cypher/remove.result create mode 100644 test/resource/unit_test/remove/cypher/remove.test create mode 100644 test/resource/unit_test/set/cypher/set.result create mode 100644 test/resource/unit_test/set/cypher/set.test create mode 100644 test/resource/unit_test/topn/cypher/topn.result create mode 100644 test/resource/unit_test/topn/cypher/topn.test create mode 100644 test/resource/unit_test/undefined_var/cypher/undefined_var.result create mode 100644 test/resource/unit_test/undefined_var/cypher/undefined_var.test create mode 100644 test/resource/unit_test/union/cypher/union.result create mode 100644 test/resource/unit_test/union/cypher/union.test create mode 100644 test/resource/unit_test/uniqueness/cypher/uniqueness.result create mode 100644 test/resource/unit_test/uniqueness/cypher/uniqueness.test create mode 100644 test/resource/unit_test/unwind/cypher/unwind.result create mode 100644 test/resource/unit_test/unwind/cypher/unwind.test create mode 100644 test/resource/unit_test/var_len_edge/cypher/var_len_edge.result create mode 100644 test/resource/unit_test/var_len_edge/cypher/var_len_edge.test create mode 100644 test/resource/unit_test/with/cypher/with.result create mode 100644 test/resource/unit_test/with/cypher/with.test create mode 100644 test/test_cypher_v2.cpp diff --git a/deps/geax-front-end/include/geax-front-end/ast/AstDumper.h b/deps/geax-front-end/include/geax-front-end/ast/AstDumper.h index 618b2aa9ce..b6e5782921 100644 --- a/deps/geax-front-end/include/geax-front-end/ast/AstDumper.h +++ b/deps/geax-front-end/include/geax-front-end/ast/AstDumper.h @@ -703,6 +703,15 @@ class AstDumper : public AstNodeVisitor { VISIT_PARAM_AND_CHECK_WITH_MSG(rig); return GEAXErrorCode::GEAX_SUCCEED; } + std::any visit(BSquare* node) override { + INDET_GUARD(); + VARIABLE_GUARD_WITH_TYPE_NAME(BSquare); + auto lef = node->left(); + auto rig = node->right(); + VISIT_PARAM_AND_CHECK_WITH_MSG(lef); + VISIT_PARAM_AND_CHECK_WITH_MSG(rig); + return GEAXErrorCode::GEAX_SUCCEED; + } std::any visit(BAnd* node) override { INDET_GUARD(); VARIABLE_GUARD_WITH_TYPE_NAME(BAnd); diff --git a/deps/geax-front-end/include/geax-front-end/ast/AstNode.h b/deps/geax-front-end/include/geax-front-end/ast/AstNode.h index 611b3fb6f8..4b0f3f7089 100644 --- a/deps/geax-front-end/include/geax-front-end/ast/AstNode.h +++ b/deps/geax-front-end/include/geax-front-end/ast/AstNode.h @@ -140,6 +140,7 @@ using StrArray = std::array; TYPE(BMul, kBMul, "BMul") \ TYPE(BDiv, kBDiv, "BDiv") \ TYPE(BMod, kBMod, "BMod") \ + TYPE(BSquare, kBSquare, "BSquare") \ TYPE(BOr, kBOr, "BOr") \ TYPE(BXor, kBXor, "BXor") \ TYPE(BAnd, kBAnd, "BAnd") \ diff --git a/deps/geax-front-end/include/geax-front-end/ast/AstNodeVisitor.h b/deps/geax-front-end/include/geax-front-end/ast/AstNodeVisitor.h index 35ea236217..129e67e51e 100644 --- a/deps/geax-front-end/include/geax-front-end/ast/AstNodeVisitor.h +++ b/deps/geax-front-end/include/geax-front-end/ast/AstNodeVisitor.h @@ -79,6 +79,7 @@ class BSub; class BMod; class BMul; class BDiv; +class BSquare; class BOr; class BXor; class BBitAnd; @@ -252,6 +253,7 @@ class AstNodeVisitor { virtual std::any visit(BDiv* node) = 0; virtual std::any visit(BMul* node) = 0; virtual std::any visit(BMod* node) = 0; + virtual std::any visit(BSquare* node) = 0; virtual std::any visit(BAnd* node) = 0; virtual std::any visit(BOr* node) = 0; virtual std::any visit(BXor* node) = 0; @@ -498,6 +500,7 @@ class AstExprNodeVisitorImpl : public AstNodeVisitor { virtual std::any visit(BDiv* node) override = 0; virtual std::any visit(BMul* node) override = 0; virtual std::any visit(BMod* node) override = 0; + virtual std::any visit(BSquare* node) override = 0; virtual std::any visit(BAnd* node) override = 0; virtual std::any visit(BOr* node) override = 0; virtual std::any visit(BXor* node) override = 0; @@ -892,6 +895,9 @@ class AstLabelTreeNodeVisitorImpl : public AstNodeVisitor { virtual std::any visit(BMod*) override { return GEAXErrorCode::GEAX_COMMON_NOT_SUPPORT; } + virtual std::any visit(BSquare*) override { + return GEAXErrorCode::GEAX_COMMON_NOT_SUPPORT; + } virtual std::any visit(BAnd*) override { return GEAXErrorCode::GEAX_COMMON_NOT_SUPPORT; } diff --git a/deps/geax-front-end/include/geax-front-end/ast/expr/BSquare.h b/deps/geax-front-end/include/geax-front-end/ast/expr/BSquare.h new file mode 100644 index 0000000000..82f6c266dd --- /dev/null +++ b/deps/geax-front-end/include/geax-front-end/ast/expr/BSquare.h @@ -0,0 +1,34 @@ +/** + * Copyright 2023 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#ifndef GEAXFRONTEND_AST_EXPR_BSQUARE_H_ +#define GEAXFRONTEND_AST_EXPR_BSQUARE_H_ + +#include "geax-front-end/ast/expr/BinaryOp.h" + +namespace geax { +namespace frontend { + +class BSquare : public BinaryOp { +public: + BSquare() : BinaryOp(AstNodeType::kBSquare) {} + ~BSquare() = default; + + std::any accept(AstNodeVisitor& visitor) override { return visitor.visit(this); } +}; // class BSquare + +} // namespace frontend +} // namespace geax + +#endif // GEAXFRONTEND_AST_EXPR_BSQUARE_H_ diff --git a/deps/geax-front-end/include/geax-front-end/ast/expr/ExprNodeFwd.h b/deps/geax-front-end/include/geax-front-end/ast/expr/ExprNodeFwd.h index a206c08103..efedac946c 100644 --- a/deps/geax-front-end/include/geax-front-end/ast/expr/ExprNodeFwd.h +++ b/deps/geax-front-end/include/geax-front-end/ast/expr/ExprNodeFwd.h @@ -39,6 +39,7 @@ #include "geax-front-end/ast/expr/BLike.h" #include "geax-front-end/ast/expr/BMod.h" #include "geax-front-end/ast/expr/BMul.h" +#include "geax-front-end/ast/expr/BSquare.h" #include "geax-front-end/ast/expr/BNotEqual.h" #include "geax-front-end/ast/expr/BNotGreaterThan.h" #include "geax-front-end/ast/expr/BNotSmallerThan.h" diff --git a/src/BuildCypherLib.cmake b/src/BuildCypherLib.cmake index ba4c512a56..3aec645eab 100644 --- a/src/BuildCypherLib.cmake +++ b/src/BuildCypherLib.cmake @@ -42,6 +42,7 @@ set(LGRAPH_CYPHER_SRC # find cypher/ -name "*.cpp" | sort cypher/execution_plan/ops/op_skip.cpp cypher/execution_plan/ops/op_sort.cpp cypher/execution_plan/ops/op_standalone_call.cpp + cypher/execution_plan/ops/op_gql_standalone_call.cpp cypher/execution_plan/ops/op_union.cpp cypher/execution_plan/ops/op_unwind.cpp cypher/execution_plan/ops/op_var_len_expand.cpp @@ -57,12 +58,14 @@ set(LGRAPH_CYPHER_SRC # find cypher/ -name "*.cpp" | sort cypher/graph/relationship.cpp cypher/grouping/group.cpp cypher/parser/cypher_base_visitor.cpp + cypher/parser/cypher_base_visitor_v2.cpp cypher/parser/cypher_error_listener.cpp cypher/parser/symbol_table.cpp cypher/parser/generated/LcypherLexer.cpp cypher/parser/generated/LcypherParser.cpp cypher/parser/generated/LcypherVisitor.cpp cypher/procedure/procedure.cpp + cypher/procedure/procedure_v2.cpp cypher/resultset/record.cpp cypher/monitor/monitor_manager.cpp cypher/execution_plan/optimization/rewrite/schema_rewrite.cpp diff --git a/src/cypher/arithmetic/arithmetic_expression.cpp b/src/cypher/arithmetic/arithmetic_expression.cpp index 8f38b76d08..74b2a9e9b3 100644 --- a/src/cypher/arithmetic/arithmetic_expression.cpp +++ b/src/cypher/arithmetic/arithmetic_expression.cpp @@ -21,12 +21,13 @@ #include #include #include +#include #include "cypher/cypher_exception.h" #include "cypher/cypher_types.h" +#include "cypher/procedure/utils.h" #include "cypher/parser/expression.h" #include "cypher/parser/clause.h" #include "cypher/parser/symbol_table.h" -#include "cypher/procedure/utils.h" #include "cypher/arithmetic/arithmetic_expression.h" #define CHECK_NODE(e) \ @@ -1233,6 +1234,59 @@ cypher::FieldData BuiltinFunction::PolygonWKT(RTContext *ctx, const Record &reco } } +cypher::FieldData BuiltinFunction::StartsWith(RTContext *ctx, const Record &record, + const std::vector &args) { + if (args.size() != 3) CYPHER_ARGUMENT_ERROR(); + auto prefix = args[1].Evaluate(ctx, record); + std::string prefix_str = prefix.constant.scalar.AsString(); + auto variable = args[2].Evaluate(ctx, record); + std::string variable_str = variable.constant.scalar.AsString(); + bool ret = variable_str.compare(0, prefix_str.size(), prefix_str) == 0; + return cypher::FieldData(lgraph_api::FieldData(ret)); +} + +cypher::FieldData BuiltinFunction::EndsWith(RTContext *ctx, const Record &record, + const std::vector &args) { + if (args.size() != 3) CYPHER_ARGUMENT_ERROR(); + auto postfix = args[1].Evaluate(ctx, record); + std::string postfix_str = postfix.constant.scalar.AsString(); + auto variable = args[2].Evaluate(ctx, record); + std::string variable_str = variable.constant.scalar.AsString(); + bool ret = variable_str.size() >= postfix_str.size() && + variable_str.compare(variable_str.size() - postfix_str.size(), + postfix_str.size(), postfix_str) == 0; + return cypher::FieldData(lgraph_api::FieldData(ret)); +} + +cypher::FieldData BuiltinFunction::Contains(RTContext *ctx, const Record &record, + const std::vector &args) { + if (args.size() != 3) CYPHER_ARGUMENT_ERROR(); + auto substr = args[1].Evaluate(ctx, record); + std::string substr_str = substr.constant.scalar.AsString(); + auto variable = args[2].Evaluate(ctx, record); + std::string variable_str = variable.constant.scalar.AsString(); + bool ret = variable_str.find(substr_str) != std::string::npos; + return cypher::FieldData(lgraph_api::FieldData(ret)); +} + +cypher::FieldData BuiltinFunction::Regexp(RTContext *ctx, const Record &record, + const std::vector &args) { + if (args.size() != 3) CYPHER_ARGUMENT_ERROR(); + auto regexp = args[1].Evaluate(ctx, record); + std::string regexp_str = regexp.constant.scalar.AsString(); + auto variable = args[2].Evaluate(ctx, record); + std::string variable_str = variable.constant.scalar.AsString(); + bool ret = std::regex_match(variable_str, std::regex(regexp_str)); + return cypher::FieldData(lgraph_api::FieldData(ret)); +} + +cypher::FieldData BuiltinFunction::Exists(RTContext *ctx, const Record &record, + const std::vector &args) { + // TODO(lingsu): implement in future + CYPHER_TODO(); + return cypher::FieldData(); +} + cypher::FieldData BuiltinFunction::Bin(RTContext *ctx, const Record &record, const std::vector &args) { if (args.size() != 2) CYPHER_ARGUMENT_ERROR(); diff --git a/src/cypher/arithmetic/arithmetic_expression.h b/src/cypher/arithmetic/arithmetic_expression.h index f16c583a32..69f6f69b7e 100644 --- a/src/cypher/arithmetic/arithmetic_expression.h +++ b/src/cypher/arithmetic/arithmetic_expression.h @@ -343,6 +343,22 @@ struct BuiltinFunction { static cypher::FieldData PolygonWKT(RTContext *ctx, const Record &record, const std::vector &args); + + static cypher::FieldData StartsWith(RTContext *ctx, const Record &record, + const std::vector &args); + + static cypher::FieldData EndsWith(RTContext *ctx, const Record &record, + const std::vector &args); + + static cypher::FieldData Contains(RTContext *ctx, const Record &record, + const std::vector &args); + + static cypher::FieldData Regexp(RTContext *ctx, const Record &record, + const std::vector &args); + + static cypher::FieldData Exists(RTContext *ctx, const Record &record, + const std::vector &args); + /* binary function (open cypher extension) */ static cypher::FieldData Bin(RTContext *ctx, const Record &record, const std::vector &args); @@ -550,6 +566,11 @@ struct ArithOpNode { ae_registered_funcs.emplace("polygon", BuiltinFunction::Polygon); ae_registered_funcs.emplace("polygonwkb", BuiltinFunction::PolygonWKB); ae_registered_funcs.emplace("polygonwkt", BuiltinFunction::PolygonWKT); + ae_registered_funcs.emplace("startswith", BuiltinFunction::StartsWith); + ae_registered_funcs.emplace("endswith", BuiltinFunction::EndsWith); + ae_registered_funcs.emplace("contains", BuiltinFunction::Contains); + ae_registered_funcs.emplace("regexp", BuiltinFunction::Regexp); + ae_registered_funcs.emplace("exists", BuiltinFunction::Exists); /* native API-like functions */ ae_registered_funcs.emplace("native.getedgefield", BuiltinFunction::NativeGetEdgeField); diff --git a/src/cypher/arithmetic/ast_expr_evaluator.cpp b/src/cypher/arithmetic/ast_expr_evaluator.cpp index b733d6bdae..e122c2e863 100644 --- a/src/cypher/arithmetic/ast_expr_evaluator.cpp +++ b/src/cypher/arithmetic/ast_expr_evaluator.cpp @@ -42,13 +42,12 @@ #endif cypher::FieldData doCallBuiltinFunc(const std::string& name, cypher::RTContext* ctx, - const cypher::Record& record, - const std::vector &args) { + const cypher::Record& record, + const std::vector& args) { static std::unordered_map ae_registered_funcs = cypher::ArithOpNode::RegisterFuncs(); auto it = ae_registered_funcs.find(name); - if (it == ae_registered_funcs.end()) - NOT_SUPPORT_AND_THROW(); + if (it == ae_registered_funcs.end()) NOT_SUPPORT_AND_THROW(); cypher::BuiltinFunction::FUNC func = it->second; auto data = func(ctx, record, args); return data; @@ -200,6 +199,8 @@ std::any cypher::AstExprEvaluator::visit(geax::frontend::BMul* node) { DO_BINARY std::any cypher::AstExprEvaluator::visit(geax::frontend::BMod* node) { DO_BINARY_EXPR(Mod); } +std::any cypher::AstExprEvaluator::visit(geax::frontend::BSquare* node) { DO_BINARY_EXPR(Pow); } + std::any cypher::AstExprEvaluator::visit(geax::frontend::BAnd* node) { DO_BINARY_EXPR(And); } std::any cypher::AstExprEvaluator::visit(geax::frontend::BOr* node) { DO_BINARY_EXPR(Or); } @@ -328,7 +329,18 @@ std::any cypher::AstExprEvaluator::visit(geax::frontend::Windowing* node) { NOT_SUPPORT_AND_THROW(); } -std::any cypher::AstExprEvaluator::visit(geax::frontend::MkList* node) { NOT_SUPPORT_AND_THROW(); } +std::any cypher::AstExprEvaluator::visit(geax::frontend::MkList* node) { + const auto& elems = node->elems(); + std::vector<::lgraph::FieldData> fields; + fields.reserve(elems.size()); + std::vector<::lgraph::FieldData> list; + for (auto& e : elems) { + auto entry = std::any_cast(e->accept(*this)); + if (!entry.IsScalar()) NOT_SUPPORT_AND_THROW(); + list.emplace_back(entry.constant.scalar); + } + return Entry(cypher::FieldData(list)); +} std::any cypher::AstExprEvaluator::visit(geax::frontend::MkMap* node) { NOT_SUPPORT_AND_THROW(); } @@ -376,6 +388,7 @@ std::any cypher::AstExprEvaluator::visit(geax::frontend::VNone* node) { NOT_SUPP std::any cypher::AstExprEvaluator::visit(geax::frontend::Ref* node) { auto it = sym_tab_->symbols.find(node->name()); + if (it == sym_tab_->symbols.end()) NOT_SUPPORT_AND_THROW(); switch (it->second.type) { case SymbolNode::NODE: case SymbolNode::RELATIONSHIP: @@ -400,6 +413,52 @@ std::any cypher::AstExprEvaluator::visit(geax::frontend::Ref* node) { std::any cypher::AstExprEvaluator::visit(geax::frontend::Param* node) { NOT_SUPPORT_AND_THROW(); } +std::any cypher::AstExprEvaluator::visit(geax::frontend::SingleLabel* node) { + std::unordered_set set; + set.insert(std::move(node->label())); + return set; +} + +std::any cypher::AstExprEvaluator::visit(geax::frontend::LabelOr* node) { + std::unordered_set left; + checkedAnyCast(node->left()->accept(*this), left); + std::unordered_set right; + checkedAnyCast(node->left()->accept(*this), right); + left.insert(right.begin(), right.end()); + return left; +} + +std::any cypher::AstExprEvaluator::visit(geax::frontend::IsLabeled* node) { + Entry e; + checkedAnyCast(node->expr()->accept(*this), e); + CYPHER_THROW_ASSERT(e.IsNode() || e.IsRelationship()); + auto alias = e.constant.scalar.AsString(); + std::unordered_set labels; + checkedAnyCast(node->labelTree()->accept(*this), labels); + bool exist = false; + std::string label; + if (e.IsNode()) { + auto n = e.node; + CYPHER_THROW_ASSERT(n && n->IsValidAfterMaterialize(ctx_)); + label = n->ItRef()->GetLabel(); + } else if (e.IsRelationship()) { + auto rel = e.relationship; + CYPHER_THROW_ASSERT(rel && rel->ItRef()->IsValid()); + label = rel->ItRef()->GetLabel(); + } + exist = labels.count(label); + return Entry(cypher::FieldData(lgraph::FieldData(exist))); +} + +std::any cypher::AstExprEvaluator::visit(geax::frontend::IsNull* node) { + Entry e; + checkedAnyCast(node->expr()->accept(*this), e); + cypher::FieldData ret; + ret.type = FieldData::SCALAR; + ret.scalar = ::lgraph::FieldData(e.IsNull()); + return Entry(ret); +} + std::any cypher::AstExprEvaluator::reportError() { return error_msg_; } } // namespace cypher diff --git a/src/cypher/arithmetic/ast_expr_evaluator.h b/src/cypher/arithmetic/ast_expr_evaluator.h index d340b609a4..d0ca82b0ca 100644 --- a/src/cypher/arithmetic/ast_expr_evaluator.h +++ b/src/cypher/arithmetic/ast_expr_evaluator.h @@ -31,6 +31,16 @@ namespace cypher { +template +void checkedAnyCast(const std::any& s, TargetType& d) { + try { + d = std::any_cast(s); + } catch (...) { + // TODO(lingsu): remove in future + assert(false); + } +} + class AstExprEvaluator : public geax::frontend::AstExprNodeVisitorImpl { public: AstExprEvaluator() = delete; @@ -54,7 +64,9 @@ class AstExprEvaluator : public geax::frontend::AstExprNodeVisitorImpl { record_ = record; agg_pos_ = 0; visit_mode_ = VisitMode::EVALUATE; - return std::any_cast(expr_->accept(*this)); + Entry entry; + checkedAnyCast(expr_->accept(*this), entry); + return entry; } void Aggregate(RTContext* ctx, const Record* record) { @@ -95,6 +107,7 @@ class AstExprEvaluator : public geax::frontend::AstExprNodeVisitorImpl { std::any visit(geax::frontend::BDiv* node) override; std::any visit(geax::frontend::BMul* node) override; std::any visit(geax::frontend::BMod* node) override; + std::any visit(geax::frontend::BSquare* node) override; std::any visit(geax::frontend::BAnd* node) override; std::any visit(geax::frontend::BOr* node) override; std::any visit(geax::frontend::BXor* node) override; @@ -133,6 +146,10 @@ class AstExprEvaluator : public geax::frontend::AstExprNodeVisitorImpl { std::any visit(geax::frontend::VNone* node) override; std::any visit(geax::frontend::Ref* node) override; std::any visit(geax::frontend::Param* node) override; + std::any visit(geax::frontend::SingleLabel* node) override; + std::any visit(geax::frontend::LabelOr* node) override; + std::any visit(geax::frontend::IsLabeled* node) override; + std::any visit(geax::frontend::IsNull* node) override; std::any reportError() override; diff --git a/src/cypher/execution_plan/clause_read_only_decider.h b/src/cypher/execution_plan/clause_read_only_decider.h new file mode 100644 index 0000000000..a7563e40df --- /dev/null +++ b/src/cypher/execution_plan/clause_read_only_decider.h @@ -0,0 +1,49 @@ +/** + * Copyright 2023 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License") {} + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#pragma once + +#include "cypher/utils/ast_node_visitor_impl.h" + +namespace cypher { + +class ClauseReadOnlyDecider : public cypher::AstNodeVisitorImpl { + public: + ClauseReadOnlyDecider() {} + + virtual ~ClauseReadOnlyDecider() = default; + + bool IsReadOnly() { + return read_only_; + } + + geax::frontend::GEAXErrorCode Build(geax::frontend::AstNode* root) { + return std::any_cast(root->accept(*this)); + } + + private: + std::any visit(geax::frontend::AmbientLinearQueryStatement* node) override { + read_only_ = true; + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; + } + + std::any visit(geax::frontend::LinearDataModifyingStatement* node) override { + read_only_ = false; + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; + } + + bool read_only_ = true; +}; + +} // namespace cypher diff --git a/src/cypher/execution_plan/execution_plan_maker.cpp b/src/cypher/execution_plan/execution_plan_maker.cpp index d1f267eea6..393f6b74b0 100644 --- a/src/cypher/execution_plan/execution_plan_maker.cpp +++ b/src/cypher/execution_plan/execution_plan_maker.cpp @@ -249,9 +249,6 @@ void ExecutionPlanMaker::_AddScanOp(const SymbolTable* sym_tab, Node* node, std::any ExecutionPlanMaker::visit(geax::frontend::GraphPattern* node) { auto& path_patterns = node->pathPatterns(); - if (path_patterns.size() > 1) { - NOT_SUPPORT(); - } for (auto path_pattern : path_patterns) { ACCEPT_AND_CHECK_WITH_ERROR_MSG(path_pattern); } @@ -293,9 +290,15 @@ std::any ExecutionPlanMaker::visit(geax::frontend::PathChain* node) { if (tails.size() == 0) { return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } + // TODO(lingsu): generate the pattern graph + // and select the starting point and end point according to the pattern graph for (auto [edge, end_node] : tails) { start_t_ = node_t_; + is_end_path_ = true; + equal_filter_.push_back(nullptr); + has_filter_per_level_.push_back(false); ACCEPT_AND_CHECK_WITH_ERROR_MSG(end_node); + is_end_path_ = false; ACCEPT_AND_CHECK_WITH_ERROR_MSG(edge); auto& start = pattern_graph.GetNode(start_t_->Alias()); auto& relp = pattern_graph.GetRelationship(relp_t_->Alias()); @@ -308,10 +311,16 @@ std::any ExecutionPlanMaker::visit(geax::frontend::PathChain* node) { expand_op = new ExpandAll(&pattern_graph, &start, &end, &relp); } expand_ops.emplace_back(expand_op); + if (has_filter_per_level_[filter_level_]) { + OpFilter* filter = new OpFilter(std::make_shared( + equal_filter_[filter_level_], pattern_graphs_[cur_pattern_graph_].symbol_table)); + expand_ops.push_back(filter); + } if (op_filter_ != nullptr) { expand_ops.push_back(op_filter_); op_filter_ = nullptr; } + ++filter_level_; } std::reverse(expand_ops.begin(), expand_ops.end()); if (auto op = _SingleBranchConnect(expand_ops)) { @@ -349,7 +358,9 @@ std::any ExecutionPlanMaker::visit(geax::frontend::Edge* node) { ClauseGuard cg(node->type(), cur_types_); relp_t_ = std::make_shared(); auto filler = node->filler(); - ACCEPT_AND_CHECK_WITH_ERROR_MSG(filler); + if (filler) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(filler); + } return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } @@ -377,6 +388,15 @@ std::any ExecutionPlanMaker::visit(geax::frontend::ElementFiller* node) { for (auto predicate : predicates) { ACCEPT_AND_CHECK_WITH_ERROR_MSG(predicate); } + + if (is_end_path_ && has_filter_per_level_[filter_level_]) { + auto expr = equal_filter_[filter_level_]; + auto field = (geax::frontend::GetField*)expr->left(); + auto ref = objAlloc_.allocate(); + auto name = variable.value(); + ref->setName(std::move(name)); + field->setExpr(ref); + } return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } @@ -402,11 +422,17 @@ std::any ExecutionPlanMaker::visit(geax::frontend::SingleLabel* node) { } else if ((ClauseGuard::InClause(geax::frontend::AstNodeType::kEdge, cur_types_))) { relp_t_->AddType(node->label()); return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; + } else if ((ClauseGuard::InClause(geax::frontend::AstNodeType::kIsLabeled, cur_types_))) { + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } NOT_SUPPORT(); } -std::any ExecutionPlanMaker::visit(geax::frontend::LabelOr* node) { NOT_SUPPORT(); } +std::any ExecutionPlanMaker::visit(geax::frontend::LabelOr* node) { + if (node->left()) ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->left()); + if (node->right()) ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->right()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any ExecutionPlanMaker::visit(geax::frontend::LabelAnd* node) { NOT_SUPPORT(); } @@ -421,15 +447,41 @@ std::any ExecutionPlanMaker::visit(geax::frontend::PropStruct* node) { Property p; auto [key, value] = property; p.field = key; + + geax::frontend::BEqual* expr = nullptr; + geax::frontend::GetField* field = nullptr; + if (is_end_path_) { + expr = objAlloc_.allocate(); + field = objAlloc_.allocate(); + std::string fieldName = key; + field->setFieldName(std::move(fieldName)); + expr->setLeft(field); + has_filter_per_level_[filter_level_] = true; + equal_filter_[filter_level_] = expr; + } if (value->type() == geax::frontend::AstNodeType::kVString) { p.type = Property::VALUE; p.value = lgraph::FieldData(((geax::frontend::VString*)value)->val()); + if (is_end_path_) { + auto right = objAlloc_.allocate(); + std::string str = ((geax::frontend::VString*)value)->val(); + right->setVal(std::move(str)); + expr->setRight(right); + } } else if (value->type() == geax::frontend::AstNodeType::kVInt) { p.type = Property::VALUE; p.value = lgraph::FieldData(((geax::frontend::VInt*)value)->val()); + if (is_end_path_) { + auto right = objAlloc_.allocate(); + right->setVal(((geax::frontend::VInt*)value)->val()); + expr->setRight(right); + } } else if (value->type() == geax::frontend::AstNodeType::kRef) { p.type = Property::VARIABLE; p.value = lgraph::FieldData(((geax::frontend::Ref*)value)->name()); + if (is_end_path_) { + NOT_SUPPORT(); + } } else { NOT_SUPPORT(); } @@ -516,6 +568,8 @@ std::any ExecutionPlanMaker::visit(geax::frontend::BMul* node) { NOT_SUPPORT(); std::any ExecutionPlanMaker::visit(geax::frontend::BMod* node) { NOT_SUPPORT(); } +std::any ExecutionPlanMaker::visit(geax::frontend::BSquare* node) { NOT_SUPPORT(); } + std::any ExecutionPlanMaker::visit(geax::frontend::BAnd* node) { NOT_SUPPORT(); } std::any ExecutionPlanMaker::visit(geax::frontend::BOr* node) { NOT_SUPPORT(); } @@ -600,7 +654,12 @@ std::any ExecutionPlanMaker::visit(geax::frontend::IsSourceOf* node) { NOT_SUPPO std::any ExecutionPlanMaker::visit(geax::frontend::IsDestinationOf* node) { NOT_SUPPORT(); } -std::any ExecutionPlanMaker::visit(geax::frontend::IsLabeled* node) { NOT_SUPPORT(); } +std::any ExecutionPlanMaker::visit(geax::frontend::IsLabeled* node) { + ClauseGuard cg(node->type(), cur_types_); + if (node->expr()) ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->expr()); + if (node->labelTree()) ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->labelTree()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any ExecutionPlanMaker::visit(geax::frontend::Same* node) { NOT_SUPPORT(); } @@ -681,7 +740,11 @@ std::any ExecutionPlanMaker::visit(geax::frontend::QueryStatement* node) { return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } -std::any ExecutionPlanMaker::visit(geax::frontend::StandaloneCallStatement* node) { NOT_SUPPORT(); } +std::any ExecutionPlanMaker::visit(geax::frontend::StandaloneCallStatement* node) { + auto stmt = node->procedureStatement(); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(stmt); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any ExecutionPlanMaker::visit(geax::frontend::JoinQueryExpression* node) { auto head = node->head(); @@ -738,11 +801,51 @@ std::any ExecutionPlanMaker::visit(geax::frontend::FilterStatement* node) { std::any ExecutionPlanMaker::visit(geax::frontend::CallQueryStatement* node) { NOT_SUPPORT(); } -std::any ExecutionPlanMaker::visit(geax::frontend::CallProcedureStatement* node) { NOT_SUPPORT(); } +std::any ExecutionPlanMaker::visit(geax::frontend::CallProcedureStatement* node) { + auto procedure = node->procedureCall(); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(procedure); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any ExecutionPlanMaker::visit(geax::frontend::InlineProcedureCall* node) { NOT_SUPPORT(); } -std::any ExecutionPlanMaker::visit(geax::frontend::NamedProcedureCall* node) { NOT_SUPPORT(); } +std::any ExecutionPlanMaker::visit(geax::frontend::NamedProcedureCall* node) { + std::string name = std::get(node->name()); + std::vector expand_ops; + auto op = new GqlStandaloneCall(name, node->args(), node->yield(), + pattern_graphs_[cur_pattern_graph_].symbol_table); + expand_ops.emplace_back(op); + auto produce = new ProduceResults(); + expand_ops.emplace_back(produce); + std::reverse(expand_ops.begin(), expand_ops.end()); + if (auto op = _SingleBranchConnect(expand_ops)) { + _UpdateStreamRoot(op, pattern_graph_root_[cur_pattern_graph_]); + } + + auto p = global_ptable_v2.GetProcedureV2(name); + if (p == nullptr) { + result_info_.header.colums.emplace_back(name); + } else { + auto& yield = node->yield(); + auto& result = p->signature.result_list; + if (!yield.has_value()) { + for (auto& r : result) { + result_info_.header.colums.emplace_back(r.name, r.name, false, r.type); + } + } else { + auto& items = yield.value()->items(); + for (auto& item : items) { + for (auto& r : result) { + if (std::get<0>(item) == r.name) { + result_info_.header.colums.emplace_back(r.name, r.name, false, r.type); + break; + } + } + } + } + } + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any ExecutionPlanMaker::visit(geax::frontend::ForStatement* node) { NOT_SUPPORT(); } @@ -815,6 +918,20 @@ std::any ExecutionPlanMaker::visit(geax::frontend::PrimitiveResultStatement* nod order_by_items.emplace_back(std::make_pair(i, !order_by_field->order())); break; } + } else if (auto field = + dynamic_cast(order_by_field->field())) { + if (auto order_by_ref = dynamic_cast(field->expr())) { + auto field_name = std::get<0>(items[i]); + std::string field_name_str = order_by_ref->name(); + field_name_str.append("."); + field_name_str.append(field->fieldName()); + if (field_name_str == field_name) { + order_by_items.emplace_back(std::make_pair(i, !order_by_field->order())); + break; + } + } else { + NOT_SUPPORT(); + } } else { NOT_SUPPORT(); } @@ -871,7 +988,22 @@ std::any ExecutionPlanMaker::visit(geax::frontend::PrimitiveResultStatement* nod std::any ExecutionPlanMaker::visit(geax::frontend::CatalogModifyStatement* node) { NOT_SUPPORT(); } std::any ExecutionPlanMaker::visit(geax::frontend::LinearDataModifyingStatement* node) { - NOT_SUPPORT(); + auto& queryStatements = node->queryStatements(); + for (auto queryStatement : queryStatements) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(queryStatement); + } + auto& modifyStatements_ = node->modifyStatements(); + for (auto modifyStatement : modifyStatements_) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(modifyStatement); + } + if (node->resultStatement().has_value()) { + auto resultStatement = node->resultStatement().value(); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(resultStatement); + } else { + auto result = new ProduceResults(); + _UpdateStreamRoot(result, pattern_graph_root_[cur_pattern_graph_]); + } + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } std::any ExecutionPlanMaker::visit(geax::frontend::InsertStatement* node) { NOT_SUPPORT(); } diff --git a/src/cypher/execution_plan/execution_plan_maker.h b/src/cypher/execution_plan/execution_plan_maker.h index 13f4f0c130..c22f0b8781 100644 --- a/src/cypher/execution_plan/execution_plan_maker.h +++ b/src/cypher/execution_plan/execution_plan_maker.h @@ -16,6 +16,7 @@ #include #include "geax-front-end/ast/AstNode.h" +#include "geax-front-end/common/ObjectAllocator.h" #include "cypher/graph/graph.h" #include "cypher/execution_plan/ops/op.h" @@ -23,8 +24,10 @@ namespace cypher { class ExecutionPlanMaker : public geax::frontend::AstNodeVisitor { public: - explicit ExecutionPlanMaker(std::vector& pattern_graphs) - : pattern_graphs_(pattern_graphs) {} + ExecutionPlanMaker(std::vector& pattern_graphs, + geax::common::ObjectArenaAllocator& alloc) + : pattern_graphs_(pattern_graphs) + , objAlloc_(alloc) {} ~ExecutionPlanMaker() = default; geax::frontend::GEAXErrorCode Build(geax::frontend::AstNode* astNode, OpBase*& root); std::string ErrorMsg() { return error_msg_; } @@ -44,6 +47,11 @@ class ExecutionPlanMaker : public geax::frontend::AstNodeVisitor { std::shared_ptr start_t_; std::shared_ptr relp_t_; OpFilter* op_filter_ = nullptr; + geax::common::ObjectArenaAllocator& objAlloc_; + std::vector equal_filter_; + std::vector has_filter_per_level_; + uint32_t filter_level_ = 0; + bool is_end_path_ = false; private: DISABLE_COPY(ExecutionPlanMaker); @@ -114,6 +122,7 @@ class ExecutionPlanMaker : public geax::frontend::AstNodeVisitor { std::any visit(geax::frontend::BDiv* node) override; std::any visit(geax::frontend::BMul* node) override; std::any visit(geax::frontend::BMod* node) override; + std::any visit(geax::frontend::BSquare* node) override; std::any visit(geax::frontend::BAnd* node) override; std::any visit(geax::frontend::BOr* node) override; std::any visit(geax::frontend::BXor* node) override; diff --git a/src/cypher/execution_plan/execution_plan_v2.cpp b/src/cypher/execution_plan/execution_plan_v2.cpp index 2356d9d535..cc2c2a9c83 100644 --- a/src/cypher/execution_plan/execution_plan_v2.cpp +++ b/src/cypher/execution_plan/execution_plan_v2.cpp @@ -17,6 +17,7 @@ #include "cypher/execution_plan/pattern_graph_maker.h" #include "cypher/execution_plan/optimization/locate_node_by_indexed_prop.h" #include "cypher/execution_plan/execution_plan_v2.h" +#include "cypher/execution_plan/clause_read_only_decider.h" namespace cypher { @@ -33,7 +34,7 @@ geax::frontend::GEAXErrorCode ExecutionPlanV2::Build(geax::frontend::AstNode* as } LOG_DEBUG() << DumpGraph(); // build execution plan - ExecutionPlanMaker execution_plan_maker(pattern_graphs_); + ExecutionPlanMaker execution_plan_maker(pattern_graphs_, obj_alloc_); ret = execution_plan_maker.Build(astNode, root_); if (ret != geax::frontend::GEAXErrorCode::GEAX_SUCCEED) { error_msg_ = execution_plan_maker.ErrorMsg(); @@ -45,6 +46,10 @@ geax::frontend::GEAXErrorCode ExecutionPlanV2::Build(geax::frontend::AstNode* as LocateNodeByIndexedProp locate_node_by_indexed_prop; locate_node_by_indexed_prop.Execute(Root()); LOG_DEBUG() << DumpPlan(0, false); + + ClauseReadOnlyDecider decider; + ret = decider.Build(astNode); + read_only_ = decider.IsReadOnly(); return ret; } diff --git a/src/cypher/execution_plan/execution_plan_v2.h b/src/cypher/execution_plan/execution_plan_v2.h index 4683796296..46cb022154 100644 --- a/src/cypher/execution_plan/execution_plan_v2.h +++ b/src/cypher/execution_plan/execution_plan_v2.h @@ -15,6 +15,7 @@ #pragma once #include "geax-front-end/ast/AstNode.h" +#include "geax-front-end/common/ObjectAllocator.h" #include "cypher/execution_plan/ops/op.h" namespace cypher { @@ -28,6 +29,7 @@ class ExecutionPlanV2 { std::string DumpGraph() const; std::string ErrorMsg(); OpBase* Root(); + void SetReadOnly(bool read_only) { read_only_ = read_only; } private: bool read_only_ = true; @@ -35,6 +37,7 @@ class ExecutionPlanV2 { std::vector pattern_graphs_; OpBase* root_ = nullptr; std::string error_msg_; + geax::common::ObjectArenaAllocator obj_alloc_; private: DISABLE_COPY(ExecutionPlanV2); diff --git a/src/cypher/execution_plan/ops/op.h b/src/cypher/execution_plan/ops/op.h index f645d487d8..151c784135 100644 --- a/src/cypher/execution_plan/ops/op.h +++ b/src/cypher/execution_plan/ops/op.h @@ -66,7 +66,7 @@ enum OpType { MERGE, TOPN, UNION, - NODE_BY_ID_SEEK, + NODE_BY_ID_SEEK }; struct OpStats { diff --git a/src/cypher/execution_plan/ops/op_gql_standalone_call.cpp b/src/cypher/execution_plan/ops/op_gql_standalone_call.cpp new file mode 100644 index 0000000000..7f01e29384 --- /dev/null +++ b/src/cypher/execution_plan/ops/op_gql_standalone_call.cpp @@ -0,0 +1,96 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#include "procedure/utils.h" +#include "cypher/execution_plan/ops/op_gql_standalone_call.h" +#include "procedure/procedure.h" +#include "resultset/record.h" +#include "server/json_convert.h" +#include "arithmetic/arithmetic_expression.h" +#include "tools/lgraph_log.h" + +cypher::OpBase::OpResult cypher::GqlStandaloneCall::RealConsume(RTContext *ctx) { + auto names = fma_common::Split(func_name_, "."); + if (names.size() > 2 && names[0] == "plugin") { + CYPHER_TODO(); + } else { + std::vector records; + std::vector _yield_items; + std::vector parameters; + parameters.reserve(args_.size()); + for (auto expr : args_) { + ArithExprNode node(expr, symbol_table_); + // TODO(lingsu): dummy record + parameters.emplace_back(node.Evaluate(ctx, Record(1))); + } + procedure_->function(ctx, nullptr, parameters, _yield_items, &records); + auto &header = ctx->result_->Header(); + for (auto &r : records) { + auto record = ctx->result_->MutableRecord(); + int idx = 0; + for (auto &v : r.values) { + auto title = header[idx].first; + auto type = header[idx].second; + switch (type) { + case lgraph_api::LGraphType::NODE: + CYPHER_TODO(); + break; + case lgraph_api::LGraphType::RELATIONSHIP: + CYPHER_TODO(); + break; + case lgraph_api::LGraphType::ANY: + if (v.type == Entry::RecordEntryType::CONSTANT && + v.constant.type == cypher::FieldData::FieldType::SCALAR) { + record->Insert(title, lgraph::FieldData(v.constant.scalar)); + } else { + record->Insert(title, lgraph::FieldData(v.ToString())); + } + break; + case lgraph_api::LGraphType::PATH: + // TODO(anyone): PATH is undefine + record->Insert(title, lgraph::FieldData(v.ToString())); + break; + case lgraph_api::LGraphType::MAP: + { + auto obj = lgraph_rfc::FieldDataToJson(v.constant.scalar); + std::map map; + for (auto &o : obj.items()) { + map[o.key()] = lgraph_rfc::JsonToFieldData(o.value()); + } + record->Insert(title, map); + break; + } + case lgraph_api::LGraphType::LIST: + { + auto obj = lgraph_rfc::FieldDataToJson(v.constant.scalar); + std::vector list; + for (auto &o : obj) { + list.emplace_back(lgraph_rfc::JsonToFieldData(o)); + } + record->Insert(title, list); + break; + } + default: + if (v.constant.array != nullptr) { + record->Insert(title, lgraph::FieldData(v.ToString())); + } else { + record->Insert(title, v.constant.scalar); + } + } + idx++; + } + } + } + return OP_DEPLETED; +} diff --git a/src/cypher/execution_plan/ops/op_gql_standalone_call.h b/src/cypher/execution_plan/ops/op_gql_standalone_call.h new file mode 100644 index 0000000000..54afa47fbf --- /dev/null +++ b/src/cypher/execution_plan/ops/op_gql_standalone_call.h @@ -0,0 +1,63 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#pragma once + +#include "procedure/procedure_v2.h" +#include "cypher/execution_plan/ops/op.h" + +namespace cypher { + // TODO(lingsu): rename in the future +class GqlStandaloneCall : public OpBase { + const std::string func_name_; + const std::vector& args_; + const std::optional& yield_; + ProcedureV2 *procedure_ = nullptr; + const SymbolTable& symbol_table_; + + public: + GqlStandaloneCall(const std::string& func_name, + const std::vector& args, + const std::optional& yield, + const SymbolTable& symbol_table) + : OpBase(OpType::STANDALONE_CALL, "Standalone Call") + , func_name_(func_name) + , args_(args) + , yield_(yield) + , symbol_table_(symbol_table) {} + + OpResult Initialize(RTContext *ctx) override { + auto p = global_ptable_v2.GetProcedureV2(func_name_); + if (!p) { + throw lgraph::EvaluationException("unregistered standalone function: " + func_name_); + } + procedure_ = p; + return OP_OK; + } + + OpResult RealConsume(RTContext *ctx) override; + + OpResult ResetImpl(bool complete = false) override { return OP_OK; } + + std::string ToString() const override { + std::string str(name); + str.append(" [").append(func_name_).append("]"); + return str; + } + + CYPHER_DEFINE_VISITABLE() + + CYPHER_DEFINE_CONST_VISITABLE() +}; +} // namespace cypher diff --git a/src/cypher/execution_plan/ops/ops.h b/src/cypher/execution_plan/ops/ops.h index 02aa4504a8..0e681cf831 100644 --- a/src/cypher/execution_plan/ops/ops.h +++ b/src/cypher/execution_plan/ops/ops.h @@ -25,6 +25,7 @@ #include "cypher/execution_plan/ops/op_expand_all.h" #include "cypher/execution_plan/ops/op_create.h" #include "cypher/execution_plan/ops/op_standalone_call.h" +#include "cypher/execution_plan/ops/op_gql_standalone_call.h" #include "cypher/execution_plan/ops/op_var_len_expand.h" #include "cypher/execution_plan/ops/op_var_len_expand_into.h" #include "cypher/execution_plan/ops/op_inquery_call.h" diff --git a/src/cypher/execution_plan/pattern_graph_maker.cpp b/src/cypher/execution_plan/pattern_graph_maker.cpp index fe33c36268..105465a227 100644 --- a/src/cypher/execution_plan/pattern_graph_maker.cpp +++ b/src/cypher/execution_plan/pattern_graph_maker.cpp @@ -16,7 +16,6 @@ #include "cypher/utils/geax_util.h" #include "cypher/execution_plan/clause_guard.h" #include "cypher/execution_plan/pattern_graph_maker.h" -#include "tools/lgraph_log.h" namespace cypher { @@ -28,9 +27,6 @@ geax::frontend::GEAXErrorCode PatternGraphMaker::Build(geax::frontend::AstNode* std::any PatternGraphMaker::visit(geax::frontend::GraphPattern* node) { auto& path_patterns = node->pathPatterns(); - if (path_patterns.size() > 1) { - NOT_SUPPORT(); - } for (auto path_pattern : path_patterns) { ACCEPT_AND_CHECK_WITH_ERROR_MSG(path_pattern); } @@ -114,6 +110,10 @@ std::any PatternGraphMaker::visit(geax::frontend::Node* node) { node_t_ = std::make_shared(); if (ClauseGuard::InClause(geax::frontend::AstNodeType::kMatchStatement, cur_types_)) { node_t_->derivation_ = Node::Derivation::MATCHED; + } else if (ClauseGuard::InClause(geax::frontend::AstNodeType::kInsertStatement, cur_types_)) { + node_t_->derivation_ = Node::Derivation::CREATED; + } else { + NOT_SUPPORT(); } auto filler = node->filler(); ACCEPT_AND_CHECK_WITH_ERROR_MSG(filler); @@ -128,6 +128,8 @@ std::any PatternGraphMaker::visit(geax::frontend::Edge* node) { auto& pattern_graph = pattern_graphs_[cur_pattern_graph_]; if (ClauseGuard::InClause(geax::frontend::AstNodeType::kMatchStatement, cur_types_)) { relp_t_->derivation_ = Relationship::Derivation::MATCHED; + } else if (ClauseGuard::InClause(geax::frontend::AstNodeType::kInsertStatement, cur_types_)) { + relp_t_->derivation_ = Relationship::Derivation::CREATED; } else { NOT_SUPPORT(); } @@ -228,44 +230,58 @@ std::any PatternGraphMaker::visit(geax::frontend::SingleLabel* node) { } else if ((ClauseGuard::InClause(geax::frontend::AstNodeType::kEdge, cur_types_))) { relp_t_->AddType(node->label()); return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; + } else if ((ClauseGuard::InClause(geax::frontend::AstNodeType::kIsLabeled, cur_types_))) { + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } NOT_SUPPORT(); } -std::any PatternGraphMaker::visit(geax::frontend::LabelOr* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::LabelOr* node) { + if (node->left()) + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->left()); + if (node->right()) + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->right()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any PatternGraphMaker::visit(geax::frontend::LabelAnd* node) { NOT_SUPPORT(); } std::any PatternGraphMaker::visit(geax::frontend::LabelNot* node) { NOT_SUPPORT(); } std::any PatternGraphMaker::visit(geax::frontend::PropStruct* node) { - auto& properties = node->properties(); - if (properties.size() != 1) { - NOT_SUPPORT(); - } - auto property = node->properties()[0]; - Property p; - auto [key, value] = property; - p.field = key; - if (value->type() == geax::frontend::AstNodeType::kVString) { - p.type = Property::VALUE; - p.value = lgraph::FieldData(((geax::frontend::VString*)value)->val()); - } else if (value->type() == geax::frontend::AstNodeType::kVInt) { - p.type = Property::VALUE; - p.value = lgraph::FieldData(((geax::frontend::VInt*)value)->val()); - } else if (value->type() == geax::frontend::AstNodeType::kRef) { - p.type = Property::VARIABLE; - p.value = lgraph::FieldData(((geax::frontend::Ref*)value)->name()); - } else { + if (ClauseGuard::InClause(geax::frontend::AstNodeType::kMatchStatement, cur_types_)) { + auto& properties = node->properties(); + if (properties.size() != 1) { + NOT_SUPPORT(); + } + auto property = node->properties()[0]; + Property p; + auto [key, value] = property; + p.field = key; + if (value->type() == geax::frontend::AstNodeType::kVString) { + p.type = Property::VALUE; + p.value = lgraph::FieldData(((geax::frontend::VString*)value)->val()); + } else if (value->type() == geax::frontend::AstNodeType::kVInt) { + p.type = Property::VALUE; + p.value = lgraph::FieldData(((geax::frontend::VInt*)value)->val()); + } else if (value->type() == geax::frontend::AstNodeType::kRef) { + p.type = Property::VARIABLE; + p.value = lgraph::FieldData(((geax::frontend::Ref*)value)->name()); + } else { + NOT_SUPPORT(); + } + if (ClauseGuard::InClause(geax::frontend::AstNodeType::kNode, cur_types_)) { + node_t_->SetProperty(p); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; + } else if (ClauseGuard::InClause(geax::frontend::AstNodeType::kEdge, cur_types_)) { + NOT_SUPPORT(); + } NOT_SUPPORT(); - } - if (ClauseGuard::InClause(geax::frontend::AstNodeType::kNode, cur_types_)) { - node_t_->SetProperty(p); + } else if (ClauseGuard::InClause(geax::frontend::AstNodeType::kInsertStatement, cur_types_)) { return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; - } else if (ClauseGuard::InClause(geax::frontend::AstNodeType::kEdge, cur_types_)) { - NOT_SUPPORT(); + } else { + NOT_SUPPORT(); } - NOT_SUPPORT(); } std::any PatternGraphMaker::visit(geax::frontend::YieldField* node) { NOT_SUPPORT(); } @@ -408,6 +424,12 @@ std::any PatternGraphMaker::visit(geax::frontend::BMod* node) { return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } +std::any PatternGraphMaker::visit(geax::frontend::BSquare* node) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->left()); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->right()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} + std::any PatternGraphMaker::visit(geax::frontend::BAnd* node) { ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->left()); ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->right()); @@ -622,7 +644,10 @@ std::any PatternGraphMaker::visit(geax::frontend::Ref* node) { std::any PatternGraphMaker::visit(geax::frontend::Param* node) { NOT_SUPPORT(); } -std::any PatternGraphMaker::visit(geax::frontend::IsNull* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::IsNull* node) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->expr()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any PatternGraphMaker::visit(geax::frontend::IsDirected* node) { NOT_SUPPORT(); } @@ -632,7 +657,12 @@ std::any PatternGraphMaker::visit(geax::frontend::IsSourceOf* node) { NOT_SUPPOR std::any PatternGraphMaker::visit(geax::frontend::IsDestinationOf* node) { NOT_SUPPORT(); } -std::any PatternGraphMaker::visit(geax::frontend::IsLabeled* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::IsLabeled* node) { + ClauseGuard cg(node->type(), cur_types_); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->expr()); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->labelTree()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any PatternGraphMaker::visit(geax::frontend::Same* node) { NOT_SUPPORT(); } @@ -732,7 +762,9 @@ std::any PatternGraphMaker::visit(geax::frontend::QueryStatement* node) { return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } -std::any PatternGraphMaker::visit(geax::frontend::StandaloneCallStatement* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::StandaloneCallStatement* node) { + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any PatternGraphMaker::visit(geax::frontend::JoinQueryExpression* node) { auto head = node->head(); @@ -822,16 +854,39 @@ std::any PatternGraphMaker::visit(geax::frontend::PrimitiveResultStatement* node std::any PatternGraphMaker::visit(geax::frontend::CatalogModifyStatement* node) { NOT_SUPPORT(); } std::any PatternGraphMaker::visit(geax::frontend::LinearDataModifyingStatement* node) { - NOT_SUPPORT(); + auto& queryStatements = node->queryStatements(); + for (auto queryStatement : queryStatements) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(queryStatement); + } + auto& modifyStatements_ = node->modifyStatements(); + for (auto modifyStatement : modifyStatements_) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(modifyStatement); + } + if (node->resultStatement().has_value()) { + auto resultStatement = node->resultStatement().value(); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(resultStatement); + } + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } -std::any PatternGraphMaker::visit(geax::frontend::InsertStatement* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::InsertStatement* node) { + ClauseGuard cg(node->type(), cur_types_); + auto& paths = node->paths(); + for (auto path : paths) { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(path); + } + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any PatternGraphMaker::visit(geax::frontend::ReplaceStatement* node) { NOT_SUPPORT(); } -std::any PatternGraphMaker::visit(geax::frontend::SetStatement* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::SetStatement* node) { + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} -std::any PatternGraphMaker::visit(geax::frontend::DeleteStatement* node) { NOT_SUPPORT(); } +std::any PatternGraphMaker::visit(geax::frontend::DeleteStatement* node) { + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; +} std::any PatternGraphMaker::visit(geax::frontend::RemoveStatement* node) { NOT_SUPPORT(); } diff --git a/src/cypher/execution_plan/pattern_graph_maker.h b/src/cypher/execution_plan/pattern_graph_maker.h index 270c75e72d..921fc103c6 100644 --- a/src/cypher/execution_plan/pattern_graph_maker.h +++ b/src/cypher/execution_plan/pattern_graph_maker.h @@ -19,10 +19,12 @@ #include "cypher/graph/graph.h" namespace cypher { +// TODO(lingsu): rename in the future class PatternGraphMaker : public geax::frontend::AstNodeVisitor { public: explicit PatternGraphMaker(std::vector& pattern_graphs) : pattern_graphs_(pattern_graphs) {} + geax::frontend::GEAXErrorCode Build(geax::frontend::AstNode* astNode); std::string ErrorMsg() { return error_msg_; } @@ -86,6 +88,7 @@ class PatternGraphMaker : public geax::frontend::AstNodeVisitor { std::any visit(geax::frontend::BDiv* node) override; std::any visit(geax::frontend::BMul* node) override; std::any visit(geax::frontend::BMod* node) override; + std::any visit(geax::frontend::BSquare* node) override; std::any visit(geax::frontend::BAnd* node) override; std::any visit(geax::frontend::BOr* node) override; std::any visit(geax::frontend::BXor* node) override; diff --git a/src/cypher/parser/cypher_base_visitor_v2.cpp b/src/cypher/parser/cypher_base_visitor_v2.cpp new file mode 100644 index 0000000000..a1711d3480 --- /dev/null +++ b/src/cypher/parser/cypher_base_visitor_v2.cpp @@ -0,0 +1,1701 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ +#include "cypher/parser/cypher_base_visitor_v2.h" +#include "cypher/utils/geax_util.h" +#include "cypher/parser/data_typedef.h" +#include "cypher/cypher_exception.h" +#include "geax-front-end/ast/AstNodeVisitor.h" +#include "cypher/parser/generated/LcypherParser.h" + +namespace parser { + +#ifndef ALLOC_GEAOBJECT +#define ALLOC_GEAOBJECT(obj) objAlloc_.allocate() +#endif // !ALLOC_GEAOBJECT + +#ifndef SWITCH_CONTEXT_VISIT +#define SWITCH_CONTEXT_VISIT(ctx, current) \ + ({ \ + geax::frontend::AstNode *prev = node_; \ + node_ = current; \ + ctx->accept(this); \ + node_ = prev; \ + }) +#endif // !SWITCH_CONTEXT_VISIT + +#ifndef SWITCH_CONTEXT_VISIT_CHILDREN +#define SWITCH_CONTEXT_VISIT_CHILDREN(ctx, current) \ + ({ \ + geax::frontend::AstNode *prev = node_; \ + node_ = current; \ + visitChildren(ctx); \ + node_ = prev; \ + }) +#endif // !SWITCH_CONTEXT_VISIT_CHILDREN + +template +void checkedCast(Base *b, Drive *&d) { + static_assert(std::is_base_of::value, + "type `Base` must be the base of type `Drive`"); + d = dynamic_cast(b); + assert(d); +} + +template +void checkedAnyCast(const std::any& s, TargetType*& d) { + try { + d = std::any_cast(s); + } catch (...) { + // TODO(lingsu): remove in future + assert(false); + } +} +template +void checkedAnyCast(const std::any& s, TargetType& d) { + try { + d = std::any_cast(s); + } catch (...) { + // TODO(lingsu): remove in future + assert(false); + } +} + +const std::unordered_map + CypherBaseVisitorV2::S_AGG_LIST = { + {"sum", geax::frontend::GeneralSetFunction::kSum}, + {"avg", geax::frontend::GeneralSetFunction::kAvg}, + {"max", geax::frontend::GeneralSetFunction::kMax}, + {"min", geax::frontend::GeneralSetFunction::kMin}, + {"count", geax::frontend::GeneralSetFunction::kCount}, + {"collect", geax::frontend::GeneralSetFunction::kCollect} +}; + +std::string CypherBaseVisitorV2::GetFullText(antlr4::ParserRuleContext *ruleCtx) const { + if (ruleCtx->children.size() == 0) { + return ""; + } + auto *startToken = ruleCtx->getStart(); + auto *stopToken = ruleCtx->getStop(); + antlr4::misc::Interval interval(startToken->getStartIndex(), stopToken->getStopIndex()); + return ruleCtx->getStart()->getInputStream()->getText(interval); +} + +CypherBaseVisitorV2::CypherBaseVisitorV2(geax::common::ObjectArenaAllocator &objAlloc, + antlr4::tree::ParseTree *tree) + : objAlloc_(objAlloc) + , node_(ALLOC_GEAOBJECT(geax::frontend::NormalTransaction)) + , anonymous_idx_(0) { + tree->accept(this); +} + +std::any CypherBaseVisitorV2::visitOC_Cypher(LcypherParser::OC_CypherContext *ctx) { + return visitChildren(ctx); +} + +std::string CypherBaseVisitorV2::GenAnonymousAlias(bool is_node) { + std::string alias(ANONYMOUS); + if (is_node) { + alias.append("N").append(std::to_string(anonymous_idx_)); + } else { + alias.append("R").append(std::to_string(anonymous_idx_)); + } + anonymous_idx_++; + return alias; +} + +// TODO(lingsu): support EXPLAIN +std::any CypherBaseVisitorV2::visitOC_Statement(LcypherParser::OC_StatementContext *ctx) { + geax::frontend::NormalTransaction *node = nullptr; + checkedCast(node_, node); + if (ctx->EXPLAIN()) { + NOT_SUPPORT_AND_THROW(); + } else if (ctx->PROFILE()) { + NOT_SUPPORT_AND_THROW(); + } else { + auto body = ALLOC_GEAOBJECT(geax::frontend::ProcedureBody); + node->setProcedureBody(body); + SWITCH_CONTEXT_VISIT_CHILDREN(ctx, body); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Query(LcypherParser::OC_QueryContext *ctx) { + return visitChildren(ctx); + geax::frontend::ProcedureBody *node = nullptr; + checkedCast(node_, node); + auto headStmt = ALLOC_GEAOBJECT(geax::frontend::StatementWithYield); + node->appendStatement(headStmt); + SWITCH_CONTEXT_VISIT_CHILDREN(ctx, headStmt); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_RegularQuery(LcypherParser::OC_RegularQueryContext *ctx) { + visit(ctx->oC_SingleQuery()); + for (auto token : ctx->oC_Union()) { + visit(token); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Union(LcypherParser::OC_UnionContext *ctx) { + NOT_SUPPORT_AND_THROW(); +} + +std::any CypherBaseVisitorV2::visitOC_SingleQuery(LcypherParser::OC_SingleQueryContext *ctx) { + if (ctx->oC_MultiPartQuery()) { + return visit(ctx->oC_MultiPartQuery()); + } else { + return visit(ctx->oC_SinglePartQuery()); + } +} + +std::any CypherBaseVisitorV2::visitOC_SinglePartQuery( + LcypherParser::OC_SinglePartQueryContext *ctx) { + if (ctx->oC_ReadingClause().size() > 2) NOT_SUPPORT_AND_THROW(); + geax::frontend::ProcedureBody *body = nullptr; + checkedCast(node_, body); + auto node = ALLOC_GEAOBJECT(geax::frontend::StatementWithYield); + body->appendStatement(node); + if (ctx->oC_UpdatingClause().empty()) { + VisitGuard guard(VisitType::kReadingClause, visit_types_); + auto stmt = ALLOC_GEAOBJECT(geax::frontend::QueryStatement); + node->setStatement(stmt); + auto join = ALLOC_GEAOBJECT(geax::frontend::JoinQueryExpression); + stmt->setJoinQuery(join); + auto co = ALLOC_GEAOBJECT(geax::frontend::CompositeQueryStatement); + join->setHead(co); + auto l = ALLOC_GEAOBJECT(geax::frontend::AmbientLinearQueryStatement); + co->setHead(l); + SWITCH_CONTEXT_VISIT_CHILDREN(ctx, l); + } else { + VisitGuard guard(VisitType::kUpdatingClause, visit_types_); + auto stmt = ALLOC_GEAOBJECT(geax::frontend::LinearDataModifyingStatement); + node->setStatement(stmt); + SWITCH_CONTEXT_VISIT_CHILDREN(ctx, stmt); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_MultiPartQuery(LcypherParser::OC_MultiPartQueryContext *ctx) { + geax::frontend::ProcedureBody *body = nullptr; + checkedCast(node_, body); + std::vector> clause; + std::vector temp; + for (auto child : ctx->children) { + if (typeid(*child) == typeid(parser::LcypherParser::OC_ReadingClauseContext)) { + temp.push_back(child); + } else if (typeid(*child) == typeid(parser::LcypherParser::OC_UpdatingClauseContext)) { + temp.push_back(child); + } else if (typeid(*child) == typeid(parser::LcypherParser::OC_WithContext)) { + temp.push_back(child); + clause.emplace_back(temp); + temp.clear(); + } + } + if (ctx->oC_UpdatingClause().empty()) { + VisitGuard guard(VisitType::kReadingClause, visit_types_); + for (auto &level_clause : clause) { + auto node = ALLOC_GEAOBJECT(geax::frontend::StatementWithYield); + body->appendStatement(node); + auto stmt = ALLOC_GEAOBJECT(geax::frontend::QueryStatement); + node->setStatement(stmt); + auto join = ALLOC_GEAOBJECT(geax::frontend::JoinQueryExpression); + stmt->setJoinQuery(join); + auto co = ALLOC_GEAOBJECT(geax::frontend::CompositeQueryStatement); + join->setHead(co); + auto l = ALLOC_GEAOBJECT(geax::frontend::AmbientLinearQueryStatement); + co->setHead(l); + for (auto c : level_clause) { + SWITCH_CONTEXT_VISIT(c, l); + } + } + } else { + VisitGuard guard(VisitType::kUpdatingClause, visit_types_); + for (auto &level_clause : clause) { + auto node = ALLOC_GEAOBJECT(geax::frontend::StatementWithYield); + body->appendStatement(node); + auto stmt = ALLOC_GEAOBJECT(geax::frontend::LinearDataModifyingStatement); + node->setStatement(stmt); + for (auto c : level_clause) { + SWITCH_CONTEXT_VISIT(c, stmt); + } + } + } + SWITCH_CONTEXT_VISIT(ctx->oC_SinglePartQuery(), body); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_UpdatingClause(LcypherParser::OC_UpdatingClauseContext *ctx) { + return visitChildren(ctx); +} + +std::any CypherBaseVisitorV2::visitOC_ReadingClause(LcypherParser::OC_ReadingClauseContext *ctx) { + return visitChildren(ctx); +} + +std::any CypherBaseVisitorV2::visitOC_Match(LcypherParser::OC_MatchContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingClause, visit_types_)) { + geax::frontend::AmbientLinearQueryStatement *node = nullptr; + checkedCast(node_, node); + auto match = ALLOC_GEAOBJECT(geax::frontend::MatchStatement); + node->appendQueryStatement(match); + if (ctx->OPTIONAL_()) match->setStatementMode(geax::frontend::StatementMode::kOptional); + auto graph_pattern = ALLOC_GEAOBJECT(geax::frontend::GraphPattern); + match->setGraphPattern(graph_pattern); + VisitGuard guard(VisitType::kReadingPattern, visit_types_); + SWITCH_CONTEXT_VISIT(ctx->oC_Pattern(), graph_pattern); + if (ctx->oC_Where()) { + SWITCH_CONTEXT_VISIT(ctx->oC_Where(), graph_pattern); + } + + } else if (VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + VisitGuard guard(VisitType::kMatchPattern, visit_types_); + visit(ctx->oC_Pattern()); + if (ctx->oC_Where()) { + CYPHER_THROW_ASSERT(!node->queryStatements().empty() && node->queryStatements()[0]); + geax::frontend::MatchStatement *match = nullptr; + checkedCast(node->queryStatements()[0], match); + SWITCH_CONTEXT_VISIT(ctx->oC_Where(), match->graphPattern()); + } + } + + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Unwind(LcypherParser::OC_UnwindContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Merge(LcypherParser::OC_MergeContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_MergeAction(LcypherParser::OC_MergeActionContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Create(LcypherParser::OC_CreateContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingClause, visit_types_)) { + NOT_SUPPORT_AND_THROW(); + } else if (VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + auto insert = ALLOC_GEAOBJECT(geax::frontend::InsertStatement); + node->appendModifyStatement(insert); + VisitGuard guard(VisitType::kUpdatingPattern, visit_types_); + SWITCH_CONTEXT_VISIT(ctx->oC_Pattern(), insert); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Set(LcypherParser::OC_SetContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingClause, visit_types_)) { + NOT_SUPPORT_AND_THROW(); + } else if (VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + for (auto &item : ctx->oC_SetItem()) { + auto stmt = ALLOC_GEAOBJECT(geax::frontend::SetStatement); + node->appendModifyStatement(stmt); + SWITCH_CONTEXT_VISIT(item, stmt); + } + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_SetItem(LcypherParser::OC_SetItemContext *ctx) { + geax::frontend::SetStatement *node = nullptr; + checkedCast(node_, node); + if (ctx->oC_PropertyExpression()) { + auto update = ALLOC_GEAOBJECT(geax::frontend::UpdateProperties); + node->appendItem(update); + VisitGuard guard(VisitType::kSetVariable, visit_types_); + SWITCH_CONTEXT_VISIT(ctx->oC_PropertyExpression(), update); + geax::frontend::Expr *expr = nullptr; + VisitGuard guardNull(VisitType::kSetNull, visit_types_); + checkedAnyCast(visit(ctx->oC_Expression()), expr); + auto &prop = update->structs()->properties(); + // so ugly!!! + geax::frontend::Expr **src = const_cast(&(std::get<1>(prop[0]))); + *src = expr; + } else { + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Variable()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string variable = vstr->val(); + auto update = ALLOC_GEAOBJECT(geax::frontend::UpdateProperties); + node->appendItem(update); + update->setV(std::move(variable)); + if (ctx->oC_Expression()) { + VisitGuard guard(VisitType::kSetVariable, visit_types_); + SWITCH_CONTEXT_VISIT(ctx->oC_Expression(), update); + } else { + NOT_SUPPORT_AND_THROW(); + } + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Delete(LcypherParser::OC_DeleteContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingClause, visit_types_)) { + NOT_SUPPORT_AND_THROW(); + } else if (VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + auto del = ALLOC_GEAOBJECT(geax::frontend::DeleteStatement); + node->appendModifyStatement(del); + for (auto e : ctx->oC_Expression()) { + VisitGuard guard(VisitType::kDeleteVariable, visit_types_); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(e), expr); + geax::frontend::VString *str; + checkedCast(expr, str); + std::string field = str->val(); + del->appendItem(std::move(field)); + } + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Remove(LcypherParser::OC_RemoveContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_RemoveItem(LcypherParser::OC_RemoveItemContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_InQueryCall(LcypherParser::OC_InQueryCallContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_StandaloneCall(LcypherParser::OC_StandaloneCallContext *ctx) { + geax::frontend::ProcedureBody *body = nullptr; + checkedCast(node_, body); + auto node = ALLOC_GEAOBJECT(geax::frontend::StatementWithYield); + body->appendStatement(node); + auto stand = ALLOC_GEAOBJECT(geax::frontend::StandaloneCallStatement); + node->setStatement(stand); + auto procedure = ALLOC_GEAOBJECT(geax::frontend::CallProcedureStatement); + stand->setProcedureStatement(procedure); + auto named_procedure = ALLOC_GEAOBJECT(geax::frontend::NamedProcedureCall); + procedure->setProcedureCall(named_procedure); + if (ctx->oC_ExplicitProcedureInvocation()) { + SWITCH_CONTEXT_VISIT(ctx->oC_ExplicitProcedureInvocation(), named_procedure); + } else if (ctx->oC_ImplicitProcedureInvocation()) { + SWITCH_CONTEXT_VISIT(ctx->oC_ImplicitProcedureInvocation(), named_procedure); + } + if (ctx->oC_YieldItems()) { + NOT_SUPPORT_AND_THROW(); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_YieldItems(LcypherParser::OC_YieldItemsContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_YieldItem(LcypherParser::OC_YieldItemContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_With(LcypherParser::OC_WithContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingClause, visit_types_)) { + geax::frontend::AmbientLinearQueryStatement *node = nullptr; + checkedCast(node_, node); + auto result = ALLOC_GEAOBJECT(geax::frontend::PrimitiveResultStatement); + result->setDistinct(ctx->DISTINCT() != nullptr); + node->setResultStatement(result); + SWITCH_CONTEXT_VISIT(ctx->oC_ReturnBody(), result); + } else if (VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + auto result = ALLOC_GEAOBJECT(geax::frontend::PrimitiveResultStatement); + result->setDistinct(ctx->DISTINCT() != nullptr); + node->setResultStatement(result); + SWITCH_CONTEXT_VISIT(ctx->oC_ReturnBody(), result); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Return(LcypherParser::OC_ReturnContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingClause, visit_types_)) { + geax::frontend::AmbientLinearQueryStatement *node = nullptr; + checkedCast(node_, node); + auto result = ALLOC_GEAOBJECT(geax::frontend::PrimitiveResultStatement); + result->setDistinct(ctx->DISTINCT() != nullptr); + node->setResultStatement(result); + SWITCH_CONTEXT_VISIT(ctx->oC_ReturnBody(), result); + } else if (VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + auto result = ALLOC_GEAOBJECT(geax::frontend::PrimitiveResultStatement); + result->setDistinct(ctx->DISTINCT() != nullptr); + node->setResultStatement(result); + SWITCH_CONTEXT_VISIT(ctx->oC_ReturnBody(), result); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_ReturnBody(LcypherParser::OC_ReturnBodyContext *ctx) { + visit(ctx->oC_ReturnItems()); + if (ctx->oC_Order()) { + visit(ctx->oC_Order()); + } + if (ctx->oC_Limit()) { + visit(ctx->oC_Limit()); + } + if (ctx->oC_Skip()) { + visit(ctx->oC_Skip()); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_ReturnItems(LcypherParser::OC_ReturnItemsContext *ctx) { + for (auto &item : ctx->oC_ReturnItem()) { + visit(item); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_ReturnItem(LcypherParser::OC_ReturnItemContext *ctx) { + geax::frontend::PrimitiveResultStatement *node = nullptr; + checkedCast(node_, node); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()), expr); + std::string variable; + if (ctx->oC_Variable()) { + variable = ctx->oC_Variable()->getText(); + } else { + variable = GetFullText(ctx->oC_Expression()); + } + node->appendItem(std::move(variable), expr); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Order(LcypherParser::OC_OrderContext *ctx) { + for (size_t idx = 0; idx < ctx->oC_SortItem().size(); ++idx) { + visit(ctx->oC_SortItem(idx)); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Skip(LcypherParser::OC_SkipContext *ctx) { + geax::frontend::PrimitiveResultStatement *node = nullptr; + checkedCast(node_, node); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()), expr); + geax::frontend::VInt *integer = nullptr; + checkedCast(expr, integer); + node->setOffset(integer->val()); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Limit(LcypherParser::OC_LimitContext *ctx) { + geax::frontend::PrimitiveResultStatement *node = nullptr; + checkedCast(node_, node); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()), expr); + geax::frontend::VInt *integer = nullptr; + checkedCast(expr, integer); + node->setLimit(integer->val()); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_SortItem(LcypherParser::OC_SortItemContext *ctx) { + geax::frontend::PrimitiveResultStatement *node = nullptr; + checkedCast(node_, node); + auto order = ALLOC_GEAOBJECT(geax::frontend::OrderByField); + node->appendOrderBy(order); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()), expr); + bool desc = ctx->DESCENDING() != nullptr || ctx->DESC() != nullptr || + (ctx->ASCENDING() == nullptr && ctx->ASC() == nullptr); + order->setField(expr); + order->setOrder(desc); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Hint(LcypherParser::OC_HintContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Where(LcypherParser::OC_WhereContext *ctx) { + geax::frontend::GraphPattern *node = nullptr; + checkedCast(node_, node); + geax::frontend::Expr *where = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()), where); + node->setWhere(where); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Pattern(LcypherParser::OC_PatternContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingPattern, visit_types_)) { + geax::frontend::GraphPattern *node = nullptr; + checkedCast(node_, node); + for (auto &ctx_part : ctx->oC_PatternPart()) { + auto pp = ALLOC_GEAOBJECT(geax::frontend::PathPattern); + node->appendPathPattern(pp); + SWITCH_CONTEXT_VISIT(ctx_part, pp); + } + } else if (VisitGuard::InClause(VisitType::kUpdatingPattern, visit_types_)) { + for (auto &ctx_part : ctx->oC_PatternPart()) { + visit(ctx_part); + } + } else if (VisitGuard::InClause(VisitType::kMatchPattern, visit_types_)) { + geax::frontend::LinearDataModifyingStatement *node = nullptr; + checkedCast(node_, node); + for (auto &ctx_part : ctx->oC_PatternPart()) { + auto match = ALLOC_GEAOBJECT(geax::frontend::MatchStatement); + node->appendQueryStatement(match); + auto graph_pattern = ALLOC_GEAOBJECT(geax::frontend::GraphPattern); + match->setGraphPattern(graph_pattern); + auto pp = ALLOC_GEAOBJECT(geax::frontend::PathPattern); + graph_pattern->appendPathPattern(pp); + SWITCH_CONTEXT_VISIT(ctx_part, pp); + } + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_PatternPart(LcypherParser::OC_PatternPartContext *ctx) { + if (VisitGuard::InClause(VisitType::kReadingPattern, visit_types_)) { + geax::frontend::PathPattern *node = nullptr; + checkedCast(node_, node); + if (ctx->oC_Variable() != nullptr) { + // named path + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Variable()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string variable = vstr->val(); + node->setAlias(std::move(variable)); + } + auto pc = ALLOC_GEAOBJECT(geax::frontend::PathChain); + node->appendChain(pc); + SWITCH_CONTEXT_VISIT(ctx->oC_AnonymousPatternPart(), pc); + } else if (VisitGuard::InClause(VisitType::kUpdatingPattern, visit_types_)) { + geax::frontend::InsertStatement *node = nullptr; + checkedCast(node_, node); + auto pc = ALLOC_GEAOBJECT(geax::frontend::PathChain); + node->appendPath(pc); + SWITCH_CONTEXT_VISIT(ctx->oC_AnonymousPatternPart(), pc); + } else if (VisitGuard::InClause(VisitType::kMatchPattern, visit_types_)) { + geax::frontend::PathPattern *node = nullptr; + checkedCast(node_, node); + if (ctx->oC_Variable() != nullptr) { + // named path + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Variable()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string variable = vstr->val(); + node->setAlias(std::move(variable)); + } + auto pc = ALLOC_GEAOBJECT(geax::frontend::PathChain); + node->appendChain(pc); + SWITCH_CONTEXT_VISIT(ctx->oC_AnonymousPatternPart(), pc); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_AnonymousPatternPart( + LcypherParser::OC_AnonymousPatternPartContext *ctx) { + return visit(ctx->oC_PatternElement()); +} + +std::any CypherBaseVisitorV2::visitOC_PatternElement(LcypherParser::OC_PatternElementContext *ctx) { + if (ctx->oC_NodePattern() == nullptr) NOT_SUPPORT_AND_THROW(); + geax::frontend::PathChain *pathChain = nullptr; + checkedCast(node_, pathChain); + auto node = ALLOC_GEAOBJECT(geax::frontend::Node); + pathChain->setHead(node); + SWITCH_CONTEXT_VISIT(ctx->oC_NodePattern(), node); + for (auto &chain : ctx->oC_PatternElementChain()) { + SWITCH_CONTEXT_VISIT(chain, pathChain); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_NodePattern(LcypherParser::OC_NodePatternContext *ctx) { + geax::frontend::Node *node = nullptr; + checkedCast(node_, node); + auto filler = ALLOC_GEAOBJECT(geax::frontend::ElementFiller); + node->setFiller(filler); + if (ctx->oC_Variable() != nullptr) { + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Variable()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string alias = vstr->val(); + filler->setV(std::move(alias)); + } else { + // if alias is absent, generate an alias for the node + filler->setV(GenAnonymousAlias(true)); + } + + if (ctx->oC_NodeLabels() != nullptr) { + std::vector labels; + checkedAnyCast(visit(ctx->oC_NodeLabels()), labels); + if (labels.size() == 1) { + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[0])); + filler->setLabel(l); + } else if (labels.size() == 2) { + auto root = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + auto r = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[0])); + r->setLabel(std::move(labels[1])); + root->setLeft(l); + root->setRight(r); + filler->setLabel(root); + } else { + auto root = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto label = root; + for (size_t idx = 0; idx < labels.size() - 2; ++idx) { + auto o = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[idx])); + label->setLeft(l); + label->setRight(o); + label = o; + } + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + auto r = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[labels.size() - 2])); + r->setLabel(std::move(labels[labels.size() - 1])); + label->setLeft(l); + label->setRight(r); + filler->setLabel(root); + } + } + + if (ctx->oC_Properties() != nullptr) { + SWITCH_CONTEXT_VISIT(ctx->oC_Properties(), filler); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_PatternElementChain( + LcypherParser::OC_PatternElementChainContext *ctx) { + geax::frontend::PathChain *pathChain = nullptr; + checkedCast(node_, pathChain); + if (ctx->oC_RelationshipPattern() && ctx->oC_NodePattern()) { + auto edge = ALLOC_GEAOBJECT(geax::frontend::Edge); + SWITCH_CONTEXT_VISIT(ctx->oC_RelationshipPattern(), edge); + auto node = ALLOC_GEAOBJECT(geax::frontend::Node); + SWITCH_CONTEXT_VISIT(ctx->oC_NodePattern(), node); + pathChain->appendTail(edge, node); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_RelationshipPattern( + LcypherParser::OC_RelationshipPatternContext *ctx) { + geax::frontend::Edge *edge = nullptr; + checkedCast(node_, edge); + geax::frontend::EdgeDirection direction; + if (ctx->oC_LeftArrowHead() != nullptr && ctx->oC_RightArrowHead() == nullptr) { + direction = geax::frontend::EdgeDirection::kPointLeft; + } else if (ctx->oC_RightArrowHead() != nullptr && ctx->oC_LeftArrowHead() == nullptr) { + direction = geax::frontend::EdgeDirection::kPointRight; + } else { + direction = geax::frontend::EdgeDirection::kAnyDirected; + } + edge->setDirection(direction); + if (ctx->oC_RelationshipDetail()) { + geax::frontend::AstNode *prev = node_; + visit(ctx->oC_RelationshipDetail()); + node_ = prev; + } else { + auto filler = ALLOC_GEAOBJECT(geax::frontend::ElementFiller); + edge->setFiller(filler); + std::string variable = GenAnonymousAlias(false); + filler->setV(std::move(variable)); + edge->setHopRange(-1, -1); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_RelationshipDetail( + LcypherParser::OC_RelationshipDetailContext *ctx) { + geax::frontend::Edge *edge = nullptr; + checkedCast(node_, edge); + auto filler = ALLOC_GEAOBJECT(geax::frontend::ElementFiller); + edge->setFiller(filler); + + std::string variable; + if (ctx->oC_Variable() != nullptr) { + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Variable()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + variable = vstr->val(); + } else { + // if alias is absent, generate an alias for the relationship + variable = GenAnonymousAlias(false); + } + filler->setV(std::move(variable)); + + if (ctx->oC_RelationshipTypes() != nullptr) { + SWITCH_CONTEXT_VISIT(ctx->oC_RelationshipTypes(), filler); + } + + if (ctx->oC_Properties() != nullptr) { + SWITCH_CONTEXT_VISIT(ctx->oC_Properties(), filler); + } + + if (ctx->oC_RangeLiteral() != nullptr) { + SWITCH_CONTEXT_VISIT(ctx->oC_RangeLiteral(), edge); + } + + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Properties(LcypherParser::OC_PropertiesContext *ctx) { + if (ctx->oC_MapLiteral() == nullptr) { + NOT_SUPPORT_AND_THROW(); + } + if (ctx->oC_MapLiteral()) { + return visit(ctx->oC_MapLiteral()); + } + if (ctx->oC_Parameter()) { + NOT_SUPPORT_AND_THROW(); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_RelationshipTypes( + LcypherParser::OC_RelationshipTypesContext *ctx) { + geax::frontend::ElementFiller *node = nullptr; + checkedCast(node_, node); + std::vector label_strs; + for (auto &ctx_label : ctx->oC_RelTypeName()) { + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx_label), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string name = vstr->val(); + label_strs.emplace_back(name); + } + if (label_strs.size() == 1) { + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(label_strs[0])); + node->setLabel(l); + return 0; + } + if (label_strs.size() == 2) { + auto root = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(label_strs[0])); + auto r = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + r->setLabel(std::move(label_strs[1])); + root->setLeft(l); + root->setRight(r); + node->setLabel(root); + return 0; + } + auto root = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto label = root; + for (size_t idx = 0; idx < label_strs.size() - 2; ++idx) { + auto o = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(label_strs[idx])); + label->setLeft(l); + label->setRight(o); + label = o; + } + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(label_strs[label_strs.size() - 2])); + auto r = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + r->setLabel(std::move(label_strs[label_strs.size() - 1])); + label->setLeft(l); + label->setRight(r); + node->setLabel(root); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_NodeLabels(LcypherParser::OC_NodeLabelsContext *ctx) { + std::vector label_strs; + for (auto &ctx_label : ctx->oC_NodeLabel()) { + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx_label), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string name = vstr->val(); + label_strs.emplace_back(name); + } + return label_strs; +} + +std::any CypherBaseVisitorV2::visitOC_NodeLabel(LcypherParser::OC_NodeLabelContext *ctx) { + return visit(ctx->oC_LabelName()); +} + +std::any CypherBaseVisitorV2::visitOC_RangeLiteral(LcypherParser::OC_RangeLiteralContext *ctx) { + geax::frontend::Edge *edge = nullptr; + checkedCast(node_, edge); + int low = 0, hight = 0; + std::vector valid_children; + for (const auto &it : ctx->children) { + const auto &text = it->getText(); + if (!std::all_of(text.cbegin(), text.cend(), ::isspace)) { + valid_children.emplace_back(it); + } + } + switch (valid_children.size()) { + case 2: + { + if (!ctx->oC_IntegerLiteral().empty()) { + low = std::stoi(ctx->oC_IntegerLiteral(0)->getText()); + hight = low; + } else { + CYPHER_THROW_ASSERT(valid_children.at(1)->getText() == ".."); + low = 1; + hight = VAR_LEN_EXPAND_MAX_HOP; + } + break; + } + case 3: + { + if (valid_children.at(2)->getText() == "..") { + low = std::stoi(ctx->oC_IntegerLiteral(0)->getText()); + hight = VAR_LEN_EXPAND_MAX_HOP; + } else { + CYPHER_THROW_ASSERT(valid_children.at(1)->getText() == ".."); + low = 1; + hight = std::stoi(ctx->oC_IntegerLiteral(0)->getText()); + } + break; + } + case 4: + { + CYPHER_THROW_ASSERT(ctx->oC_IntegerLiteral().size() == 2); + low = std::stoi(ctx->oC_IntegerLiteral(0)->getText()); + hight = std::stoi(ctx->oC_IntegerLiteral(1)->getText()); + break; + } + default: + CYPHER_TODO(); + } + edge->setHopRange(low, hight); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_LabelName(LcypherParser::OC_LabelNameContext *ctx) { + return visit(ctx->oC_SchemaName()); +} + +std::any CypherBaseVisitorV2::visitOC_RelTypeName(LcypherParser::OC_RelTypeNameContext *ctx) { + return visit(ctx->oC_SchemaName()); +} + +std::any CypherBaseVisitorV2::visitOC_Expression(LcypherParser::OC_ExpressionContext *ctx) { + return ctx->oC_OrExpression()->accept(this); +} + +std::any CypherBaseVisitorV2::visitOC_OrExpression(LcypherParser::OC_OrExpressionContext *ctx) { + geax::frontend::Expr *left = nullptr, *right = nullptr; + for (size_t idx = 0; idx < ctx->oC_XorExpression().size(); ++idx) { + left = right; + checkedAnyCast(visit(ctx->oC_XorExpression(idx)), right); + if (idx > 0) { + auto op = ALLOC_GEAOBJECT(geax::frontend::BOr); + op->setLeft(left); + op->setRight(right); + right = op; + } + } + return right; +} + +std::any CypherBaseVisitorV2::visitOC_XorExpression(LcypherParser::OC_XorExpressionContext *ctx) { + geax::frontend::Expr *left = nullptr, *right = nullptr; + for (size_t idx = 0; idx < ctx->oC_AndExpression().size(); ++idx) { + left = right; + checkedAnyCast(visit(ctx->oC_AndExpression(idx)), right); + if (idx > 0) { + auto op = ALLOC_GEAOBJECT(geax::frontend::BXor); + op->setLeft(left); + op->setRight(right); + right = op; + } + } + return right; +} + +std::any CypherBaseVisitorV2::visitOC_AndExpression(LcypherParser::OC_AndExpressionContext *ctx) { + geax::frontend::Expr *left = nullptr, *right = nullptr; + for (size_t idx = 0; idx < ctx->oC_NotExpression().size(); ++idx) { + left = right; + checkedAnyCast(visit(ctx->oC_NotExpression(idx)), right); + if (idx > 0) { + auto op = ALLOC_GEAOBJECT(geax::frontend::BAnd); + op->setLeft(left); + op->setRight(right); + right = op; + } + } + return right; +} + +std::any CypherBaseVisitorV2::visitOC_NotExpression(LcypherParser::OC_NotExpressionContext *ctx) { + if (ctx->NOT().size() % 2) { + auto op = ALLOC_GEAOBJECT(geax::frontend::Not); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_ComparisonExpression()), expr); + op->setExpr(expr); + return (geax::frontend::Expr *)op; + } else { + return visit(ctx->oC_ComparisonExpression()); + } +} + +std::any CypherBaseVisitorV2::visitOC_ComparisonExpression( + LcypherParser::OC_ComparisonExpressionContext *ctx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_AddOrSubtractExpression()), expr); + if (ctx->oC_PartialComparisonExpression().empty()) return expr; + if (ctx->oC_PartialComparisonExpression().size() > 1) NOT_SUPPORT_AND_THROW(); + geax::frontend::BinaryOp *bi = nullptr; + checkedAnyCast(visit(ctx->oC_PartialComparisonExpression(0)), bi); + bi->setLeft(expr); + return (geax::frontend::Expr *)bi; +} + +std::any CypherBaseVisitorV2::visitOC_AddOrSubtractExpression( + LcypherParser::OC_AddOrSubtractExpressionContext *ctx) { + std::vector ops; + ops.reserve(ctx->children.size()); + for (auto c : ctx->children) { + if (c->getText() == "+" || c->getText() == "-") { + ops.emplace_back(c->getText()); + } + } + if (ops.size() != ctx->oC_MultiplyDivideModuloExpression().size() - 1) { + NOT_SUPPORT_AND_THROW(); + } + geax::frontend::Expr *left = nullptr, *right = nullptr; + for (size_t idx = 0; idx < ctx->oC_MultiplyDivideModuloExpression().size(); ++idx) { + left = right; + checkedAnyCast(visit(ctx->oC_MultiplyDivideModuloExpression(idx)), right); + if (idx > 0) { + geax::frontend::BinaryOp *op = nullptr; + if (ops[idx - 1] == "+") { + op = ALLOC_GEAOBJECT(geax::frontend::BAdd); + } else if (ops[idx - 1] == "-") { + op = ALLOC_GEAOBJECT(geax::frontend::BSub); + } + op->setLeft(left); + op->setRight(right); + right = op; + } + } + return right; +} + +std::any CypherBaseVisitorV2::visitOC_MultiplyDivideModuloExpression( + LcypherParser::OC_MultiplyDivideModuloExpressionContext *ctx) { + std::vector ops; + ops.reserve(ctx->children.size()); + for (auto c : ctx->children) { + if (c->getText() == "*" || c->getText() == "/" || c->getText() == "%") { + ops.emplace_back(c->getText()); + } + } + if (ops.size() != ctx->oC_PowerOfExpression().size() - 1) { + NOT_SUPPORT_AND_THROW(); + } + geax::frontend::Expr *left = nullptr, *right = nullptr; + for (size_t idx = 0; idx < ctx->oC_PowerOfExpression().size(); ++idx) { + left = right; + checkedAnyCast(visit(ctx->oC_PowerOfExpression(idx)), right); + if (idx > 0) { + geax::frontend::BinaryOp *op = nullptr; + if (ops[idx - 1] == "*") { + op = ALLOC_GEAOBJECT(geax::frontend::BMul); + } else if (ops[idx - 1] == "/") { + op = ALLOC_GEAOBJECT(geax::frontend::BDiv); + } else if (ops[idx - 1] == "%") { + op = ALLOC_GEAOBJECT(geax::frontend::BMod); + } + op->setLeft(left); + op->setRight(right); + right = op; + } + } + return right; +} + +std::any CypherBaseVisitorV2::visitOC_PowerOfExpression( + LcypherParser::OC_PowerOfExpressionContext *ctx) { + std::vector ops; + ops.reserve(ctx->children.size()); + for (auto c : ctx->children) { + if (c->getText() == "^") { + ops.emplace_back(c->getText()); + } + } + if (ops.size() != ctx->oC_UnaryAddOrSubtractExpression().size() - 1) { + NOT_SUPPORT_AND_THROW(); + } + geax::frontend::Expr *left = nullptr, *right = nullptr; + for (size_t idx = 0; idx < ctx->oC_UnaryAddOrSubtractExpression().size(); ++idx) { + left = right; + checkedAnyCast(visit(ctx->oC_UnaryAddOrSubtractExpression(idx)), right); + if (idx > 0) { + geax::frontend::BinaryOp *op = nullptr; + if (ops[idx - 1] == "^") { + op = ALLOC_GEAOBJECT(geax::frontend::BSquare); + } + op->setLeft(left); + op->setRight(right); + right = op; + } + } + return right; +} + +std::any CypherBaseVisitorV2::visitOC_UnaryAddOrSubtractExpression( + LcypherParser::OC_UnaryAddOrSubtractExpressionContext *ctx) { + int sign = 0; + if (ctx->children.size() > 1) { + for (auto &child : ctx->children) { + // TODO(anyone) not elegant + if (child->getText() == "-") sign ^= 0x1; + } + } + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_StringListNullOperatorExpression()), expr); + if (sign) { + auto neg = ALLOC_GEAOBJECT(geax::frontend::Neg); + neg->setExpr(expr); + expr = neg; + } + return expr; +} + +std::any CypherBaseVisitorV2::visitOC_StringListNullOperatorExpression( + LcypherParser::OC_StringListNullOperatorExpressionContext *ctx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_PropertyOrLabelsExpression()), expr); + if (!ctx->oC_NullOperatorExpression().empty()) { + if (ctx->oC_NullOperatorExpression().size() > 1) NOT_SUPPORT_AND_THROW(); + geax::frontend::Expr *is_null_expr = nullptr; + checkedAnyCast(visit(ctx->oC_NullOperatorExpression()[0]), is_null_expr); + if (typeid(*is_null_expr) == typeid(geax::frontend::IsNull)) { + geax::frontend::IsNull *is_null = nullptr; + checkedCast(is_null_expr, is_null); + is_null->setExpr(expr); + return (geax::frontend::Expr *)is_null; + } else if (typeid(*is_null_expr) == typeid(geax::frontend::Not)) { + geax::frontend::Not *not_expr = nullptr; + checkedCast(is_null_expr, not_expr); + geax::frontend::Expr *inner = not_expr->expr(); + geax::frontend::IsNull *is_null = nullptr; + checkedCast(inner, is_null); + is_null->setExpr(expr); + return (geax::frontend::Expr *)is_null; + } else { + NOT_SUPPORT_AND_THROW(); + } + } else if (!ctx->oC_StringOperatorExpression().empty()) { + if (ctx->oC_StringOperatorExpression().size() > 1) NOT_SUPPORT_AND_THROW(); + for (auto e : ctx->oC_StringOperatorExpression()) { + geax::frontend::Expr *func_expr = nullptr; + checkedAnyCast(visit(e), func_expr); + geax::frontend::Function *func = nullptr; + checkedCast(func_expr, func); + func->appendArg(expr); + return (geax::frontend::Expr *)func; + } + } else if (!ctx->oC_ListOperatorExpression().empty()) { + if (ctx->oC_ListOperatorExpression().size() > 1) NOT_SUPPORT_AND_THROW(); + auto list_op_expr = ctx->oC_ListOperatorExpression(0); + if (list_op_expr->IN()) { + CYPHER_THROW_ASSERT(list_op_expr->oC_PropertyOrLabelsExpression()); + geax::frontend::Expr *right = nullptr; + checkedAnyCast(visit(list_op_expr->oC_PropertyOrLabelsExpression()), right); + CYPHER_THROW_ASSERT(list_op_expr->oC_PropertyOrLabelsExpression()); + auto bin = ALLOC_GEAOBJECT(geax::frontend::BIn); + bin->setLeft(expr); + bin->setRight(right); + return (geax::frontend::Expr *)bin; + } else { + CYPHER_THROW_ASSERT(!list_op_expr->oC_Expression().empty()); + auto func = ALLOC_GEAOBJECT(geax::frontend::Function); + func->setName("subscript"); + func->appendArg(expr); + for (size_t idx = 0; idx < list_op_expr->oC_Expression().size(); ++idx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(list_op_expr->oC_Expression(idx)), expr); + func->appendArg(expr); + } + return (geax::frontend::Expr *)func; + } + } + return expr; +} + +std::any CypherBaseVisitorV2::visitOC_ListOperatorExpression( + LcypherParser::OC_ListOperatorExpressionContext *ctx) { + return visitChildren(ctx); +} + +std::any CypherBaseVisitorV2::visitOC_StringOperatorExpression( + LcypherParser::OC_StringOperatorExpressionContext *ctx) { + std::string name = ctx->STARTS() ? "StartsWith" + : ctx->ENDS() ? "EndsWith" + : ctx->CONTAINS() ? "Contains" + : "Regexp"; + auto func = ALLOC_GEAOBJECT(geax::frontend::Function); + func->setName(std::move(name)); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_PropertyOrLabelsExpression()), expr); + func->appendArg(expr); + return (geax::frontend::Expr *)func; +} + +std::any CypherBaseVisitorV2::visitOC_NullOperatorExpression( + LcypherParser::OC_NullOperatorExpressionContext *ctx) { + if (ctx->NOT()) { + auto nl = ALLOC_GEAOBJECT(geax::frontend::IsNull); + auto nt = ALLOC_GEAOBJECT(geax::frontend::Not); + nt->setExpr(nl); + return (geax::frontend::Expr *)nt; + } else { + auto nul = ALLOC_GEAOBJECT(geax::frontend::IsNull); + return (geax::frontend::Expr *)nul; + } + NOT_SUPPORT_AND_THROW(); +} + +std::any CypherBaseVisitorV2::visitOC_PropertyOrLabelsExpression( + LcypherParser::OC_PropertyOrLabelsExpressionContext *ctx) { + if (ctx->children.size() == 1) return visit(ctx->oC_Atom()); + + if (!ctx->oC_PropertyLookup().empty()) { + if (ctx->oC_PropertyLookup().size() > 1) NOT_SUPPORT_AND_THROW(); + auto field = ALLOC_GEAOBJECT(geax::frontend::GetField); + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_PropertyLookup(0)), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string field_name = vstr->val(); + field->setFieldName(std::move(field_name)); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Atom()), expr); + field->setExpr(expr); + return (geax::frontend::Expr *)field; + } + if (ctx->oC_NodeLabels()) { + std::vector labels; + checkedAnyCast(visit(ctx->oC_NodeLabels()), labels); + auto is_labeled = ALLOC_GEAOBJECT(geax::frontend::IsLabeled); + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Atom()), expr); + is_labeled->setExpr(expr); + if (labels.size() == 1) { + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[0])); + is_labeled->setLabelTree(l); + } else if (labels.size() == 2) { + auto root = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + auto r = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[0])); + r->setLabel(std::move(labels[1])); + root->setLeft(l); + root->setRight(r); + is_labeled->setLabelTree(root); + } else { + auto root = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto label = root; + for (size_t idx = 0; idx < labels.size() - 2; ++idx) { + auto o = ALLOC_GEAOBJECT(geax::frontend::LabelOr); + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[idx])); + label->setLeft(l); + label->setRight(o); + label = o; + } + auto l = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + auto r = ALLOC_GEAOBJECT(geax::frontend::SingleLabel); + l->setLabel(std::move(labels[labels.size() - 2])); + r->setLabel(std::move(labels[labels.size() - 1])); + label->setLeft(l); + label->setRight(r); + is_labeled->setLabelTree(root); + } + return (geax::frontend::Expr *)is_labeled; + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Atom(LcypherParser::OC_AtomContext *ctx) { + if (ctx->oC_Variable()) { + if (VisitGuard::InClause(VisitType::kSetVariable, visit_types_) || + VisitGuard::InClause(VisitType::kDeleteVariable, visit_types_)) { + return visit(ctx->oC_Variable()); + } else { + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Variable()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string name = vstr->val(); + auto expr = ALLOC_GEAOBJECT(geax::frontend::Ref); + expr->setName(std::move(name)); + return (geax::frontend::Expr *)expr; + } + } else if (ctx->oC_Literal()) { + return visit(ctx->oC_Literal()); + } else if (ctx->oC_FunctionInvocation()) { + return visit(ctx->oC_FunctionInvocation()); + } else if (ctx->oC_ParenthesizedExpression()) { + return visit(ctx->oC_ParenthesizedExpression()); + } else if (ctx->oC_RelationshipsPattern()) { + return visit(ctx->oC_RelationshipsPattern()); + } else if (ctx->oC_CaseExpression()) { + return visit(ctx->oC_CaseExpression()); + } else if (ctx->oC_FilterExpression()) { + return visit(ctx->oC_FilterExpression()); + } else if (ctx->oC_ListComprehension()) { + return visit(ctx->oC_ListComprehension()); + } else if (ctx->oC_PatternComprehension()) { + return visit(ctx->oC_PatternComprehension()); + } else if (ctx->oC_Parameter()) { + return visit(ctx->oC_Parameter()); + } + NOT_SUPPORT_AND_THROW(); +} + +std::any CypherBaseVisitorV2::visitOC_Literal(LcypherParser::OC_LiteralContext *ctx) { + if (ctx->StringLiteral()) { + std::string str = ctx->StringLiteral()->getText(); + CYPHER_THROW_ASSERT(!str.empty() && (str[0] == '\'' || str[0] == '\"') && + (str[str.size() - 1] == '\'' || str[str.size() - 1] == '\"')); + str = str.substr(1, str.size() - 2); + auto expr = ALLOC_GEAOBJECT(geax::frontend::VString); + expr->setVal(std::move(str)); + return (geax::frontend::Expr *)expr; + } else if (ctx->oC_NumberLiteral()) { + return visit(ctx->oC_NumberLiteral()); + } else if (ctx->oC_BooleanLiteral()) { + return visit(ctx->oC_BooleanLiteral()); + } else if (ctx->oC_MapLiteral()) { + return visit(ctx->oC_MapLiteral()); + } else if (ctx->NULL_()) { + if (VisitGuard::InClause(VisitType::kSetNull, visit_types_)) { + auto n = ALLOC_GEAOBJECT(geax::frontend::VNull); + return (geax::frontend::Expr *)n; + } else if (VisitGuard::InClause(VisitType::kSetVariable, visit_types_)) { + geax::frontend::UpdateProperties *up = nullptr; + checkedCast(node_, up); + auto prop = ALLOC_GEAOBJECT(geax::frontend::PropStruct); + up->setStructs(prop); + auto n = ALLOC_GEAOBJECT(geax::frontend::VNull); + prop->appendProperty("", n); + return (geax::frontend::Expr *)n; + } else { + auto n = ALLOC_GEAOBJECT(geax::frontend::VNull); + return (geax::frontend::Expr *)n; + } + } else if (ctx->oC_ListLiteral()) { + return visit(ctx->oC_ListLiteral()); + } + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_BooleanLiteral(LcypherParser::OC_BooleanLiteralContext *ctx) { + auto d = ALLOC_GEAOBJECT(geax::frontend::VBool); + if (ctx->TRUE_()) { + d->setVal(true); + } else { + d->setVal(false); + } + return (geax::frontend::Expr *)d; +} + +std::any CypherBaseVisitorV2::visitOC_ListLiteral(LcypherParser::OC_ListLiteralContext *ctx) { + auto list = ALLOC_GEAOBJECT(geax::frontend::MkList); + for (auto &ctx_expr : ctx->oC_Expression()) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx_expr), expr); + list->appendElem(expr); + } + return (geax::frontend::Expr *)list; +} + +std::any CypherBaseVisitorV2::visitOC_PartialComparisonExpression( + LcypherParser::OC_PartialComparisonExpressionContext *ctx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_AddOrSubtractExpression()), expr); + geax::frontend::BinaryOp *bi = nullptr; + auto predicate = ctx->getStart()->getText(); + if (predicate == "=") { + bi = ALLOC_GEAOBJECT(geax::frontend::BEqual); + } else if (predicate == "<>") { + bi = ALLOC_GEAOBJECT(geax::frontend::BNotEqual); + } else if (predicate == "<") { + bi = ALLOC_GEAOBJECT(geax::frontend::BSmallerThan); + } else if (predicate == ">") { + bi = ALLOC_GEAOBJECT(geax::frontend::BGreaterThan); + } else if (predicate == "<=") { + bi = ALLOC_GEAOBJECT(geax::frontend::BNotGreaterThan); + } else if (predicate == ">=") { + bi = ALLOC_GEAOBJECT(geax::frontend::BNotSmallerThan); + } + bi->setRight(expr); + return bi; +} + +std::any CypherBaseVisitorV2::visitOC_ParenthesizedExpression( + LcypherParser::OC_ParenthesizedExpressionContext *ctx) { + return visit(ctx->oC_Expression()); +} + +std::any CypherBaseVisitorV2::visitOC_RelationshipsPattern( + LcypherParser::OC_RelationshipsPatternContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_FilterExpression( + LcypherParser::OC_FilterExpressionContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_IdInColl(LcypherParser::OC_IdInCollContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_FunctionInvocation( + LcypherParser::OC_FunctionInvocationContext *ctx) { + std::string name; + checkedAnyCast(visit(ctx->oC_FunctionName()), name); + geax::frontend::Expr *res = nullptr; + auto it = S_AGG_LIST.find(name); + if (it != S_AGG_LIST.end()) { + auto func = ALLOC_GEAOBJECT(geax::frontend::AggFunc); + func->setFuncName(it->second); + if (ctx->DISTINCT()) { + func->setDistinct(true); + } else { + func->setDistinct(false); + } + + for (size_t idx = 0; idx < ctx->oC_Expression().size(); ++idx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression(idx)), expr); + if (idx == 0) { + func->setExpr(expr); + } else { + func->appendDistinctBy(expr); + } + } + res = func; + } else { + auto func = ALLOC_GEAOBJECT(geax::frontend::Function); + func->setName(std::move(name)); + for (size_t idx = 0; idx < ctx->oC_Expression().size(); ++idx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression(idx)), expr); + func->appendArg(expr); + } + res = func; + } + return res; +} + +std::any CypherBaseVisitorV2::visitOC_FunctionName(LcypherParser::OC_FunctionNameContext *ctx) { + if (ctx->EXISTS()) { + return std::string("EXISTS"); + } + std::string name; + if (ctx->oC_Namespace()) { + checkedAnyCast(visit(ctx->oC_Namespace()), name); + } + name.append(ctx->oC_SymbolicName()->getText()); + return name; +} + +std::any CypherBaseVisitorV2::visitOC_ExplicitProcedureInvocation( + LcypherParser::OC_ExplicitProcedureInvocationContext *ctx) { + geax::frontend::NamedProcedureCall *node = nullptr; + checkedCast(node_, node); + std::string fun_name; + checkedAnyCast(visit(ctx->oC_ProcedureName()), fun_name); + geax::frontend::StringParam name = fun_name; + node->setName(std::move(name)); + for (auto oc : ctx->oC_Expression()) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(oc), expr); + node->appendArg(expr); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_ImplicitProcedureInvocation( + LcypherParser::OC_ImplicitProcedureInvocationContext *ctx) { + geax::frontend::NamedProcedureCall *node = nullptr; + checkedCast(node_, node); + std::string fun_name; + checkedAnyCast(visit(ctx->oC_ProcedureName()), fun_name); + geax::frontend::StringParam name = fun_name; + node->setName(std::move(name)); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_ProcedureResultField( + LcypherParser::OC_ProcedureResultFieldContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_ProcedureName(LcypherParser::OC_ProcedureNameContext *ctx) { + std::string name; + if (ctx->oC_Namespace()) { + checkedAnyCast(visit(ctx->oC_Namespace()), name); + } + name.append(ctx->oC_SymbolicName()->getText()); + return name; +} + +std::any CypherBaseVisitorV2::visitOC_Namespace(LcypherParser::OC_NamespaceContext *ctx) { + std::string name_space; + for (auto &s : ctx->oC_SymbolicName()) name_space.append(s->getText()).append("."); + return name_space; +} + +std::any CypherBaseVisitorV2::visitOC_ListComprehension( + LcypherParser::OC_ListComprehensionContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_PatternComprehension( + LcypherParser::OC_PatternComprehensionContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_PropertyLookup(LcypherParser::OC_PropertyLookupContext *ctx) { + return visit(ctx->oC_PropertyKeyName()); +} + +std::any CypherBaseVisitorV2::visitOC_CaseExpression(LcypherParser::OC_CaseExpressionContext *ctx) { + auto case_clause = ALLOC_GEAOBJECT(geax::frontend::Case); + if (ctx->oC_Expression().empty()) { + for (auto caseAlternatives : ctx->oC_CaseAlternatives()) { + SWITCH_CONTEXT_VISIT(caseAlternatives, case_clause); + } + } else if (ctx->oC_Expression().size() == 2) { + for (auto caseAlternatives : ctx->oC_CaseAlternatives()) { + SWITCH_CONTEXT_VISIT(caseAlternatives, case_clause); + } + geax::frontend::Expr *head = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()[0]), head); + case_clause->setInput(head); + geax::frontend::Expr *tail = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()[1]), tail); + case_clause->setElseBody(tail); + } else if (ctx->ELSE() != nullptr) { + if (ctx->oC_Expression().size() != 1) CYPHER_TODO(); + for (auto caseAlternatives : ctx->oC_CaseAlternatives()) { + SWITCH_CONTEXT_VISIT(caseAlternatives, case_clause); + } + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()[0]), expr); + case_clause->setElseBody(expr); + } else { + for (auto caseAlternatives : ctx->oC_CaseAlternatives()) { + SWITCH_CONTEXT_VISIT(caseAlternatives, case_clause); + } + geax::frontend::Expr *head = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()[0]), head); + case_clause->setInput(head); + } + return (geax::frontend::Expr *)case_clause; +} + +std::any CypherBaseVisitorV2::visitOC_CaseAlternatives( + LcypherParser::OC_CaseAlternativesContext *ctx) { + geax::frontend::Case *node = nullptr; + checkedCast(node_, node); + geax::frontend::Expr *left = nullptr; + if (ctx->oC_Expression().size() != 2) CYPHER_TODO(); + checkedAnyCast(visit(ctx->oC_Expression()[0]), left); + geax::frontend::Expr *right = nullptr; + checkedAnyCast(visit(ctx->oC_Expression()[1]), right); + node->appendCaseBody(left, right); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Variable(LcypherParser::OC_VariableContext *ctx) { + return visit(ctx->oC_SymbolicName()); +} + +std::any CypherBaseVisitorV2::visitOC_NumberLiteral(LcypherParser::OC_NumberLiteralContext *ctx) { + if (ctx->oC_DoubleLiteral()) { + return visit(ctx->oC_DoubleLiteral()); + } else if (ctx->oC_IntegerLiteral()) { + return visit(ctx->oC_IntegerLiteral()); + } + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_MapLiteral(LcypherParser::OC_MapLiteralContext *ctx) { + geax::frontend::Expr *res = nullptr; + // this must be the fist condition, don't move!!! + if (VisitGuard::InClause(VisitType::kSetVariable, visit_types_)) { + geax::frontend::UpdateProperties *node = nullptr; + checkedCast(node_, node); + if (ctx->oC_Expression().size() != ctx->oC_PropertyKeyName().size()) + NOT_SUPPORT_AND_THROW(); + auto ps = ALLOC_GEAOBJECT(geax::frontend::PropStruct); + node->setStructs(ps); + for (size_t idx = 0; idx < ctx->oC_PropertyKeyName().size(); ++idx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression(idx)), expr); + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_PropertyKeyName(idx)), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string name = vstr->val(); + ps->appendProperty(std::move(name), expr); + } + } else if (VisitGuard::InClause(VisitType::kReadingPattern, visit_types_) || + VisitGuard::InClause(VisitType::kUpdatingClause, visit_types_)) { + geax::frontend::ElementFiller *filler = nullptr; + checkedCast(node_, filler); + if (ctx->oC_Expression().size() != ctx->oC_PropertyKeyName().size()) + NOT_SUPPORT_AND_THROW(); + auto ps = ALLOC_GEAOBJECT(geax::frontend::PropStruct); + filler->appendPredicate(ps); + for (size_t idx = 0; idx < ctx->oC_PropertyKeyName().size(); ++idx) { + geax::frontend::Expr *expr = nullptr; + checkedAnyCast(visit(ctx->oC_Expression(idx)), expr); + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_PropertyKeyName(idx)), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string name = vstr->val(); + ps->appendProperty(std::move(name), expr); + } + } else { + NOT_SUPPORT_AND_THROW(); + } + return res; +} + +std::any CypherBaseVisitorV2::visitOC_Parameter(LcypherParser::OC_ParameterContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_PropertyExpression( + LcypherParser::OC_PropertyExpressionContext *ctx) { + geax::frontend::Expr *ret = nullptr; + if (VisitGuard::InClause(VisitType::kSetVariable, visit_types_)) { + if (ctx->oC_PropertyLookup().size() > 1) NOT_SUPPORT_AND_THROW(); + geax::frontend::UpdateProperties *node = nullptr; + checkedCast(node_, node); + geax::frontend::Expr *name_expr = nullptr; + checkedAnyCast(visit(ctx->oC_Atom()), name_expr); + geax::frontend::VString *vstr = nullptr; + checkedCast(name_expr, vstr); + std::string var = vstr->val(); + node->setV(std::move(var)); + + auto ps = ALLOC_GEAOBJECT(geax::frontend::PropStruct); + node->setStructs(ps); + geax::frontend::Expr *prop = nullptr; + checkedAnyCast(visit(ctx->oC_PropertyLookup(0)), prop); + geax::frontend::VString *prop_str = nullptr; + checkedCast(prop, prop_str); + std::string property = prop_str->val(); + ps->appendProperty(std::move(property), nullptr); + } + return ret; +} + +std::any CypherBaseVisitorV2::visitOC_PropertyKeyName( + LcypherParser::OC_PropertyKeyNameContext *ctx) { + return visit(ctx->oC_SchemaName()); +} + +std::any CypherBaseVisitorV2::visitOC_IntegerLiteral(LcypherParser::OC_IntegerLiteralContext *ctx) { + auto integer = ALLOC_GEAOBJECT(geax::frontend::VInt); + integer->setVal(std::stol(ctx->getText())); + return (geax::frontend::Expr *)integer; +} + +std::any CypherBaseVisitorV2::visitOC_DoubleLiteral(LcypherParser::OC_DoubleLiteralContext *ctx) { + auto d = ALLOC_GEAOBJECT(geax::frontend::VDouble); + d->setVal(std::stod(ctx->getText())); + return (geax::frontend::Expr *)d; +} + +std::any CypherBaseVisitorV2::visitOC_SchemaName(LcypherParser::OC_SchemaNameContext *ctx) { + if (ctx->oC_ReservedWord()) { + NOT_SUPPORT_AND_THROW(); + } else { + return visitOC_SymbolicName(ctx->oC_SymbolicName()); + } + return visitChildren(ctx); +} + +std::any CypherBaseVisitorV2::visitOC_ReservedWord(LcypherParser::OC_ReservedWordContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_SymbolicName(LcypherParser::OC_SymbolicNameContext *ctx) { + auto s = ALLOC_GEAOBJECT(geax::frontend::VString); + s->setVal(ctx->getText()); + return (geax::frontend::Expr *)s; +} + +std::any CypherBaseVisitorV2::visitOC_LeftArrowHead(LcypherParser::OC_LeftArrowHeadContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_RightArrowHead(LcypherParser::OC_RightArrowHeadContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +std::any CypherBaseVisitorV2::visitOC_Dash(LcypherParser::OC_DashContext *ctx) { + NOT_SUPPORT_AND_THROW(); + return 0; +} + +} // end of namespace parser diff --git a/src/cypher/parser/cypher_base_visitor_v2.h b/src/cypher/parser/cypher_base_visitor_v2.h new file mode 100644 index 0000000000..9aed9a4c04 --- /dev/null +++ b/src/cypher/parser/cypher_base_visitor_v2.h @@ -0,0 +1,318 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +// Generated from Lcypher.g4 by ANTLR 4.9.2 + +#pragma once + +#include "antlr4-runtime/antlr4-runtime.h" +#include "parser/generated/LcypherVisitor.h" +#include "cypher/cypher_exception.h" +#include "geax-front-end/common/ObjectAllocator.h" +#include "geax-front-end/ast/Ast.h" + +#if __APPLE__ +#ifdef TRUE +#undef TRUE +#endif +#ifdef FALSE +#undef FALSE +#endif +#endif // #if __APPLE__ + +namespace parser { + +enum class VisitType { + kReadingClause, + kUpdatingClause, + kReadingPattern, + kUpdatingPattern, + kMatchPattern, + kSetVariable, + kSetNull, + kDeleteVariable +}; + +class VisitGuard { + VisitType type_; + std::unordered_set& cur_types_; + public: + VisitGuard(VisitType type, std::unordered_set& cur_types) + : type_(type), cur_types_(cur_types) { + cur_types.emplace(type_); + } + + ~VisitGuard() { cur_types_.erase(type_); } + + static bool InClause(VisitType type, const std::unordered_set& cur_types) { + return cur_types.find(type) != cur_types.end(); + } +}; + +/** + * This class provides an empty implementation of LcypherVisitor, which can be + * extended to create a visitor which only needs to handle a subset of the available methods. + */ +class CypherBaseVisitorV2 : public LcypherVisitor { + std::string error_msg_; + geax::common::ObjectArenaAllocator& objAlloc_; + geax::frontend::AstNode * node_; + size_t anonymous_idx_; + std::unordered_set visit_types_; + static const std::unordered_map S_AGG_LIST; + + public: + CypherBaseVisitorV2() = delete; + + + CypherBaseVisitorV2(geax::common::ObjectArenaAllocator& objAlloc, + antlr4::tree::ParseTree *tree); + + std::string GenAnonymousAlias(bool is_node); + + std::string GetFullText(antlr4::ParserRuleContext* ruleCtx) const; + + geax::frontend::AstNode *result() const { return node_; } + + std::any visitOC_Cypher(LcypherParser::OC_CypherContext *ctx) override; + + std::any visitOC_Statement(LcypherParser::OC_StatementContext *ctx) override; + + std::any visitOC_Query(LcypherParser::OC_QueryContext *ctx) override; + + std::any visitOC_RegularQuery(LcypherParser::OC_RegularQueryContext *ctx) override; + + std::any visitOC_Union(LcypherParser::OC_UnionContext *ctx) override; + + std::any visitOC_SingleQuery(LcypherParser::OC_SingleQueryContext *ctx) override; + + std::any visitOC_SinglePartQuery( + LcypherParser::OC_SinglePartQueryContext *ctx) override; + + std::any visitOC_MultiPartQuery(LcypherParser::OC_MultiPartQueryContext *ctx) override; + + std::any visitOC_UpdatingClause(LcypherParser::OC_UpdatingClauseContext *ctx) override; + + std::any visitOC_ReadingClause(LcypherParser::OC_ReadingClauseContext *ctx) override; + + std::any visitOC_Match(LcypherParser::OC_MatchContext *ctx) override; + + std::any visitOC_Unwind(LcypherParser::OC_UnwindContext *ctx) override; + + std::any visitOC_Merge(LcypherParser::OC_MergeContext *ctx) override; + + std::any visitOC_MergeAction(LcypherParser::OC_MergeActionContext *ctx) override; + + std::any visitOC_Create(LcypherParser::OC_CreateContext *ctx) override; + + std::any visitOC_Set(LcypherParser::OC_SetContext *ctx) override; + + std::any visitOC_SetItem(LcypherParser::OC_SetItemContext *ctx) override; + + std::any visitOC_Delete(LcypherParser::OC_DeleteContext *ctx) override; + + std::any visitOC_Remove(LcypherParser::OC_RemoveContext *ctx) override; + + std::any visitOC_RemoveItem(LcypherParser::OC_RemoveItemContext *ctx) override; + + std::any visitOC_InQueryCall(LcypherParser::OC_InQueryCallContext *ctx) override; + + std::any visitOC_StandaloneCall(LcypherParser::OC_StandaloneCallContext *ctx) override; + + std::any visitOC_YieldItems(LcypherParser::OC_YieldItemsContext *ctx) override; + + std::any visitOC_YieldItem(LcypherParser::OC_YieldItemContext *ctx) override; + + std::any visitOC_With(LcypherParser::OC_WithContext *ctx) override; + + std::any visitOC_Return(LcypherParser::OC_ReturnContext *ctx) override; + + std::any visitOC_ReturnBody(LcypherParser::OC_ReturnBodyContext *ctx) override; + + std::any visitOC_ReturnItems(LcypherParser::OC_ReturnItemsContext *ctx) override; + + std::any visitOC_ReturnItem(LcypherParser::OC_ReturnItemContext *ctx) override; + + std::any visitOC_Order(LcypherParser::OC_OrderContext *ctx) override; + + std::any visitOC_Skip(LcypherParser::OC_SkipContext *ctx) override; + + std::any visitOC_Limit(LcypherParser::OC_LimitContext *ctx) override; + + std::any visitOC_SortItem(LcypherParser::OC_SortItemContext *ctx) override; + + std::any visitOC_Hint(LcypherParser::OC_HintContext *ctx) override; + + std::any visitOC_Where(LcypherParser::OC_WhereContext *ctx) override; + + std::any visitOC_Pattern(LcypherParser::OC_PatternContext *ctx) override; + + std::any visitOC_PatternPart(LcypherParser::OC_PatternPartContext *ctx) override; + + std::any visitOC_AnonymousPatternPart( + LcypherParser::OC_AnonymousPatternPartContext *ctx) override; + + std::any visitOC_PatternElement(LcypherParser::OC_PatternElementContext *ctx) override; + + std::any visitOC_NodePattern(LcypherParser::OC_NodePatternContext *ctx) override; + + std::any visitOC_PatternElementChain( + LcypherParser::OC_PatternElementChainContext *ctx) override; + + std::any visitOC_RelationshipPattern( + LcypherParser::OC_RelationshipPatternContext *ctx) override; + + std::any visitOC_RelationshipDetail( + LcypherParser::OC_RelationshipDetailContext *ctx) override; + + std::any visitOC_Properties(LcypherParser::OC_PropertiesContext *ctx) override; + + std::any visitOC_RelationshipTypes( + LcypherParser::OC_RelationshipTypesContext *ctx) override; + + std::any visitOC_NodeLabels(LcypherParser::OC_NodeLabelsContext *ctx) override; + + std::any visitOC_NodeLabel(LcypherParser::OC_NodeLabelContext *ctx) override; + + std::any visitOC_RangeLiteral(LcypherParser::OC_RangeLiteralContext *ctx) override; + + std::any visitOC_LabelName(LcypherParser::OC_LabelNameContext *ctx) override; + + std::any visitOC_RelTypeName(LcypherParser::OC_RelTypeNameContext *ctx) override; + + std::any visitOC_Expression(LcypherParser::OC_ExpressionContext *ctx) override; + + std::any visitOC_OrExpression(LcypherParser::OC_OrExpressionContext *ctx) override; + + std::any visitOC_XorExpression(LcypherParser::OC_XorExpressionContext *ctx) override; + + std::any visitOC_AndExpression(LcypherParser::OC_AndExpressionContext *ctx) override; + + std::any visitOC_NotExpression(LcypherParser::OC_NotExpressionContext *ctx) override; + + std::any visitOC_ComparisonExpression( + LcypherParser::OC_ComparisonExpressionContext *ctx) override; + + std::any visitOC_AddOrSubtractExpression( + LcypherParser::OC_AddOrSubtractExpressionContext *ctx) override; + + std::any visitOC_MultiplyDivideModuloExpression( + LcypherParser::OC_MultiplyDivideModuloExpressionContext *ctx) override; + + std::any visitOC_PowerOfExpression( + LcypherParser::OC_PowerOfExpressionContext *ctx) override; + + std::any visitOC_UnaryAddOrSubtractExpression( + LcypherParser::OC_UnaryAddOrSubtractExpressionContext *ctx) override; + + std::any visitOC_StringListNullOperatorExpression( + LcypherParser::OC_StringListNullOperatorExpressionContext *ctx) override; + + std::any visitOC_ListOperatorExpression( + LcypherParser::OC_ListOperatorExpressionContext *ctx) override; + + std::any visitOC_StringOperatorExpression( + LcypherParser::OC_StringOperatorExpressionContext *ctx) override; + + std::any visitOC_NullOperatorExpression( + LcypherParser::OC_NullOperatorExpressionContext *ctx) override; + + std::any visitOC_PropertyOrLabelsExpression( + LcypherParser::OC_PropertyOrLabelsExpressionContext *ctx) override; + + std::any visitOC_Atom(LcypherParser::OC_AtomContext *ctx) override; + + std::any visitOC_Literal(LcypherParser::OC_LiteralContext *ctx) override; + + std::any visitOC_BooleanLiteral(LcypherParser::OC_BooleanLiteralContext *ctx) override; + + std::any visitOC_ListLiteral(LcypherParser::OC_ListLiteralContext *ctx) override; + + std::any visitOC_PartialComparisonExpression( + LcypherParser::OC_PartialComparisonExpressionContext *ctx) override; + + std::any visitOC_ParenthesizedExpression( + LcypherParser::OC_ParenthesizedExpressionContext *ctx) override; + + std::any visitOC_RelationshipsPattern( + LcypherParser::OC_RelationshipsPatternContext *ctx) override; + + std::any visitOC_FilterExpression( + LcypherParser::OC_FilterExpressionContext *ctx) override; + + std::any visitOC_IdInColl(LcypherParser::OC_IdInCollContext *ctx) override; + + std::any visitOC_FunctionInvocation( + LcypherParser::OC_FunctionInvocationContext *ctx) override; + + std::any visitOC_FunctionName(LcypherParser::OC_FunctionNameContext *ctx) override; + + std::any visitOC_ExplicitProcedureInvocation( + LcypherParser::OC_ExplicitProcedureInvocationContext *ctx) override; + + std::any visitOC_ImplicitProcedureInvocation( + LcypherParser::OC_ImplicitProcedureInvocationContext *ctx) override; + + std::any visitOC_ProcedureResultField( + LcypherParser::OC_ProcedureResultFieldContext *ctx) override; + + std::any visitOC_ProcedureName(LcypherParser::OC_ProcedureNameContext *ctx) override; + + std::any visitOC_Namespace(LcypherParser::OC_NamespaceContext *ctx) override; + + std::any visitOC_ListComprehension( + LcypherParser::OC_ListComprehensionContext *ctx) override; + + std::any visitOC_PatternComprehension( + LcypherParser::OC_PatternComprehensionContext *ctx) override; + + std::any visitOC_PropertyLookup(LcypherParser::OC_PropertyLookupContext *ctx) override; + + std::any visitOC_CaseExpression(LcypherParser::OC_CaseExpressionContext *ctx) override; + + std::any visitOC_CaseAlternatives( + LcypherParser::OC_CaseAlternativesContext *ctx) override; + + std::any visitOC_Variable(LcypherParser::OC_VariableContext *ctx) override; + + std::any visitOC_NumberLiteral(LcypherParser::OC_NumberLiteralContext *ctx) override; + + std::any visitOC_MapLiteral(LcypherParser::OC_MapLiteralContext *ctx) override; + + std::any visitOC_Parameter(LcypherParser::OC_ParameterContext *ctx) override; + + std::any visitOC_PropertyExpression( + LcypherParser::OC_PropertyExpressionContext *ctx) override; + + std::any visitOC_PropertyKeyName( + LcypherParser::OC_PropertyKeyNameContext *ctx) override; + + std::any visitOC_IntegerLiteral(LcypherParser::OC_IntegerLiteralContext *ctx) override; + + std::any visitOC_DoubleLiteral(LcypherParser::OC_DoubleLiteralContext *ctx) override; + + std::any visitOC_SchemaName(LcypherParser::OC_SchemaNameContext *ctx) override; + + std::any visitOC_ReservedWord(LcypherParser::OC_ReservedWordContext *ctx) override; + + std::any visitOC_SymbolicName(LcypherParser::OC_SymbolicNameContext *ctx) override; + + std::any visitOC_LeftArrowHead(LcypherParser::OC_LeftArrowHeadContext *ctx) override; + + std::any visitOC_RightArrowHead(LcypherParser::OC_RightArrowHeadContext *ctx) override; + + std::any visitOC_Dash(LcypherParser::OC_DashContext *ctx) override; +}; + +} // namespace parser diff --git a/src/cypher/procedure/procedure_v2.cpp b/src/cypher/procedure/procedure_v2.cpp new file mode 100644 index 0000000000..aa523e8471 --- /dev/null +++ b/src/cypher/procedure/procedure_v2.cpp @@ -0,0 +1,2984 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#include "import/import_online.h" +#include "core/field_data_helper.h" +#include "core/thread_id.h" +#include "db/galaxy.h" +#include "parser/data_typedef.h" +#include "resultset/record.h" +#include "server/state_machine.h" +#include "restful/server/json_convert.h" +#include "cypher/graph/common.h" +#include "cypher/procedure/procedure_v2.h" +#include "cypher/procedure/utils.h" +#include "butil/endpoint.h" +#include "cypher/monitor/memory_monitor_allocator.h" +#include "fma-common/encrypt.h" +#include "import/import_v3.h" + +namespace cypher { + +#define CYPHER_ARG_CHECK(pred, msg) \ + if (!(pred)) { \ + throw lgraph::ReminderException(msg); \ + } + +#define CYPHER_DB_PROCEDURE_GRAPH_CHECK() \ + do { \ + if (ctx->graph_.empty()) throw lgraph::CypherException("graph name cannot be empty"); \ + if (!ctx->ac_db_) CYPHER_INTL_ERR(); \ + if (!ctx->txn_) CYPHER_INTL_ERR(); \ + } while (0) + +typedef std::unordered_map> + EDGE_FILTER_T; + +const std::unordered_map BuiltinProcedureV2::type_map_ = + lgraph::field_data_helper::_detail::_FieldName2TypeDict_(); + +cypher::VEC_STR_V2 ProcedureTitlesV2(const std::string &procedure_name, + const cypher::VEC_STR_V2 &yield_items) { + cypher::VEC_STR_V2 titles; + auto pp = global_ptable_v2.GetProcedureV2(procedure_name); + + if (yield_items.empty()) { + for (auto &res : pp->signature.result_list) titles.emplace_back(res.name); + } else { + for (auto &item : yield_items) { + if (!pp->ContainsYieldItem(item)) { + throw lgraph::CypherException("Unknown procedure output: " + item); + } + titles.emplace_back(item); + } + } + return titles; +} + +static bool ParseIsVertex(const std::string &token) { + if (fma_common::StringEqual(token, "vertex", false)) return true; + if (fma_common::StringEqual(token, "edge", false)) return false; + THROW_CODE(InputError, "Wrong argument given for label type: must be 'vertex' or 'edge'."); + return false; +} + +void BuiltinProcedureV2::DbSubgraph(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, "This function takes 1 argrument. e.g. db.DbSubGraph(vids)"); + CYPHER_ARG_CHECK(args[0].IsArray(), "db.DbSubGraph(vids): `vids` must be list"); + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + std::set set_vids; + for (auto &vid : *args[0].constant.array) { + CYPHER_ARG_CHECK(vid.IsInteger(), "db.DbSubGraph(vids): `vid` must be int"); + set_vids.emplace(vid.integer()); + } + auto vit = ctx->txn_->GetTxn()->GetVertexIterator(); + std::vector vertices; + std::vector relationships; + for (auto vid : set_vids) { + if (!vit.Goto(vid, false)) continue; + lgraph_api::lgraph_result::Node node; + node.id = vid; + node.label = ctx->txn_->GetTxn()->GetVertexLabel(vit); + for (auto &property : ctx->txn_->GetTxn()->GetVertexFields(vit)) { + node.properties.insert(property); + } + vertices.push_back(node.ToJson()); + for (auto eit = vit.GetOutEdgeIterator(); eit.IsValid(); eit.Next()) { + lgraph_api::lgraph_result::Relationship repl; + auto uid = eit.GetUid(); + if (set_vids.find(uid.dst) == set_vids.end()) continue; + repl.id = uid.eid; + repl.src = uid.src; + repl.dst = uid.dst; + repl.label_id = uid.lid; + repl.label = ctx->txn_->GetTxn()->GetEdgeLabel(eit); + repl.forward = true; + repl.tid = uid.tid; + auto rel_fields = ctx->txn_->GetTxn()->GetEdgeFields(eit); + for (auto &property : rel_fields) { + repl.properties.insert(property); + } + relationships.push_back(repl.ToJson()); + } + } + Record r; + nlohmann::json j; + j["nodes"] = vertices; + j["relationships"] = relationships; + r.AddConstant(lgraph::FieldData(j.dump())); + records->push_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbVertexLabels(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.vertexLabels()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + auto labels = ctx->txn_->GetTxn()->GetAllLabels(true); + for (auto &l : labels) { + Record r; + r.AddConstant(lgraph::FieldData(l)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbEdgeLabels(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.edgeLabels()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + auto labels = ctx->txn_->GetTxn()->GetAllLabels(false); + for (auto &l : labels) { + Record r; + r.AddConstant(lgraph::FieldData(l)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbIndexes(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.indexes()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + auto vertex_indexes = ctx->txn_->GetTxn()->ListVertexIndexes(); + for (auto &i : vertex_indexes) { + Record r; + r.AddConstant(lgraph::FieldData(i.label)); + r.AddConstant(lgraph::FieldData(i.field)); + r.AddConstant(lgraph::FieldData("vertex")); + bool unique = false, pair_unique = false; + switch (i.type) { + case lgraph::IndexType::GlobalUniqueIndex: + unique = true; + break; + case lgraph::IndexType::PairUniqueIndex: + pair_unique = true; + break; + case lgraph::IndexType::NonuniqueIndex: + // just to pass the compilation + break; + } + r.AddConstant(lgraph::FieldData(unique)); + r.AddConstant(lgraph::FieldData(pair_unique)); + records->emplace_back(r.Snapshot()); + } + auto edge_indexes = ctx->txn_->GetTxn()->ListEdgeIndexes(); + for (auto &i : edge_indexes) { + Record r; + r.AddConstant(lgraph::FieldData(i.label)); + r.AddConstant(lgraph::FieldData(i.field)); + r.AddConstant(lgraph::FieldData("edge")); + bool unique = false, pair_unique = false; + switch (i.type) { + case lgraph::IndexType::GlobalUniqueIndex: + unique = true; + break; + case lgraph::IndexType::PairUniqueIndex: + pair_unique = true; + break; + case lgraph::IndexType::NonuniqueIndex: + // just to pass the compilation + break; + } + r.AddConstant(lgraph::FieldData(unique)); + r.AddConstant(lgraph::FieldData(pair_unique)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbListLabelIndexes(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + FMA_FMT("Function requires 2 arguments, but {} are " + "given. Usage: db.listLabelIndexes(label_name, label_type)", + args.size())) + + CYPHER_ARG_CHECK(!args[0].IsString(), FMA_FMT("{} has to be a string ", args[0].ToString())) + CYPHER_ARG_CHECK(args[0].IsString(), FMA_FMT("{} has to be a string ", args[0].ToString())) + auto label = args[0].constant.scalar.AsString(); + bool is_vertex = ParseIsVertex(label); + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + std::vector indexes; + if (is_vertex) { + indexes = ctx->txn_->GetTxn()->ListVertexIndexByLabel(label); + } else { + indexes = ctx->txn_->GetTxn()->ListEdgeIndexByLabel(label); + } + for (auto &i : indexes) { + if (i.label != label) continue; + Record r; + r.AddConstant(lgraph::FieldData(i.label)); + r.AddConstant(lgraph::FieldData(i.field)); + bool unique = false, pair_unique = false; + switch (i.type) { + case lgraph::IndexType::GlobalUniqueIndex: + unique = true; + break; + case lgraph::IndexType::PairUniqueIndex: + pair_unique = true; + break; + case lgraph::IndexType::NonuniqueIndex: + // just to pass the compilation + break; + } + r.AddConstant(lgraph::FieldData(unique)); + r.AddConstant(lgraph::FieldData(pair_unique)); + records->emplace_back(r.Snapshot()); + } +} +void BuiltinProcedureV2::DbPropertyKeys(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_TODO(); +} + +void BuiltinProcedureV2::DbWarmUp(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.warmup()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + double t1 = fma_common::GetTime(); + ctx->txn_.reset(); + ctx->ac_db_->WarmUp(); + double t2 = fma_common::GetTime(); + Record r; + r.AddConstant( + lgraph::FieldData("Warm up successful in " + std::to_string(t2 - t1) + " seconds.")); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsProcedures(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.procedures()", + args.size())) + auto pp = global_ptable.GetProcedure("dbms.procedures"); + CYPHER_THROW_ASSERT(pp && pp->ContainsYieldItem("name") && pp->ContainsYieldItem("signature")); + cypher::VEC_STR_V2 titles; + if (yield_items.empty()) { + titles.push_back("name"); + titles.push_back("signature"); + titles.push_back("read_only"); + } else { + for (auto &item : yield_items) titles.emplace_back(item); + } + std::unordered_map> lmap = { + {"name", + [](const ProcedureV2 &p, Record &r) { r.AddConstant(lgraph::FieldData(p.proc_name)); }}, + {"signature", + [](const ProcedureV2 &p, Record &r) { r.AddConstant(lgraph::FieldData(p.Signature())); }}, + {"read_only", + [](const ProcedureV2 &p, Record &r) { r.AddConstant(lgraph::FieldData(p.read_only)); }}}; + for (auto &p : global_procedures_v2) { + Record r; + for (auto &title : titles) { + lmap.find(title)->second(p, r); + } + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::_ExtractFds(const VEC_EXPR_V2 &args, std::string &label, + std::string &extra, std::vector &fds) { + using namespace parser; + CYPHER_ARG_CHECK(args.size() % SPEC_MEMBER_SIZE_V2 == 2, + "Not enough arguments. This function takes 2 or more arguments.") + CYPHER_ARG_CHECK(args[0].IsString(), FMA_FMT("{} has to be a string ", args[0].ToString())) + CYPHER_ARG_CHECK(args[1].IsString(), FMA_FMT("{} has to be a string ", args[0].ToString())) + + label = args[0].constant.scalar.AsString(); + extra = args[1].constant.scalar.AsString(); + for (int i = 0; i < (int)args.size() / 3; i++) { + CYPHER_ARG_CHECK( + args[i * SPEC_MEMBER_SIZE_V2 + 2].IsString(), + FMA_FMT("{} has to be a string ", args[i * SPEC_MEMBER_SIZE_V2 + 2].ToString())) + CYPHER_ARG_CHECK( + args[i * SPEC_MEMBER_SIZE_V2 + 3].IsScalar(), + FMA_FMT("{} has to be a variable,alternative value is " + "(NUL,BOOL,INT8,INT16,INT32,INT64,FLOAT,DOUBLE,DATE,DATETIME,STRING,BLOB) ", + args[i * SPEC_MEMBER_SIZE_V2 + 3].ToString())) + CYPHER_ARG_CHECK( + args[i * SPEC_MEMBER_SIZE_V2 + 4].IsBool(), + FMA_FMT("{} has to be a boolean ", args[i * SPEC_MEMBER_SIZE_V2 + 4].ToString())) + auto name = args[i * SPEC_MEMBER_SIZE_V2 + 2].constant.scalar.AsString(); + auto type_name = args[i * SPEC_MEMBER_SIZE_V2 + 3].constant.scalar.AsString(); + auto nullable = args[i * SPEC_MEMBER_SIZE_V2 + 4].constant.scalar.AsBool(); + + std::transform(type_name.begin(), type_name.end(), type_name.begin(), ::tolower); + auto it = type_map_.find(type_name); + if (it == type_map_.end()) { + throw lgraph::ReminderException("Unknown type name: " + type_name); + } + fds.emplace_back(name, it->second, nullable); + } +} + +void BuiltinProcedureV2::_ExtractAccessLevel( + const VEC_EXPR_V2 &args, std::string &role, + std::unordered_map &leves) { + // CYPHER_ARG_CHECK(args.size() == 2, + // "Not enough arguments. This function takes 2 or " + // "more arguments. first is a string, other arguments are map"); + // CYPHER_ARG_CHECK(args[0].IsString(), + // "wrong arguments type,has to be a string"); + // CYPHER_ARG_CHECK(args[1].type == parser::Expression::MAP, + // "wrong arguments type, has to be a map"); + // role = args[0].constant.scalar.AsString(); + // std::unordered_map temp_levels; + // for (auto &kv : args[1].Map()) { + // auto it = ValidAccessLevels.find(kv.second.constant.scalar.AsString()); + // CYPHER_ARG_CHECK(it != ValidAccessLevels.end(), "unknown access level"); + // temp_levels[kv.first] = it->second; + // } + // std::swap(leves, temp_levels); +} + +static ::std::vector<::lgraph::FieldSpec> ParseFieldSpecs(const VEC_EXPR_V2 &args, + size_t start_from) { + using namespace parser; + std::vector ret; + for (size_t i = start_from; i < args.size(); i++) { + CYPHER_ARG_CHECK(args[i].IsArray() && args[i].constant.array->size() == 3, + "Each FieldSpec must be a list of ('name', 'type' 'optional')"); + const auto &list = *args[i].constant.array; + CYPHER_ARG_CHECK(list[0].IsString() && list[1].IsString() && list[2].IsBool(), + "Each FieldSpec must be a list of (name, type [,optional])") + lgraph::FieldType ft; + if (!lgraph::field_data_helper::TryGetFieldType(list[1].AsString(), ft)) + THROW_CODE(InputError, "Illegal field type:{}", list[1]); + ret.emplace_back(list[0].AsString(), ft, list[2].AsBool()); + } + return ret; +} + +static std::vector ParseStringList(const Entry &arg, const std::string ¶m_name) { + std::vector ret; + if (arg.IsString()) { + ret.push_back(arg.constant.scalar.AsString()); + } else if (arg.IsArray()) { + for (auto &a : *arg.constant.array) { + if (_F_UNLIKELY(!a.IsString())) + THROW_CODE(InputError, + "Illegal value for parameter [{}]: must be a string or list of strings.", + param_name); + ret.push_back(a.AsString()); + } + } else { + THROW_CODE(InputError, + "Illegal value for parameter [{}]: must be a string or list of strings.", + param_name); + } + return ret; +} + +static std::string ParseStringArg(const Entry &entry, const std::string ¶m_name) { + if (_F_UNLIKELY(!entry.IsString())) + THROW_CODE(InputError, "Illegal value for parameter [{}]: must be a string.", param_name); + return entry.constant.scalar.AsString(); +} + +void BuiltinProcedureV2::DbCreateVertexLabel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() % SPEC_MEMBER_SIZE_V2 == 2, + "e.g. db.createVertexLabel(label_name, primary_fd, field_name, field_type, is_unique)"); + std::string label; + std::string primary_fd; + std::vector fds; + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + _ExtractFds(args, label, primary_fd, fds); + auto ret = ctx->ac_db_->AddLabel(true, label, fds, lgraph::VertexOptions(primary_fd)); + if (!ret) { + throw lgraph::LabelExistException(label, true); + } +} + +// params: vertex, label, primary_field, [fieldspec1], [fieldspec2]... +// params: edge, label, edge_constraints, [fieldspec1], [fieldspec2]... +void BuiltinProcedureV2::DbCreateLabel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + if (args.size() < 2) + THROW_CODE(InputError, "Not enough arguments. This function takes 2 or more arguments."); + bool is_vertex = ParseIsVertex(args[0].constant.scalar.AsString()); + std::string label = ParseStringArg(args[1], "label_name"); + std::string primary_fd; + std::vector> edge_constraints; + if (is_vertex) { + primary_fd = ParseStringArg(args[2], "primary_field"); + } else { + auto str = ParseStringArg(args[2], "edge_constraints"); + auto ec = nlohmann::json::parse(str); + for (auto &item : ec) { + if (item.size() != 2) { + THROW_CODE(InputError, "The size of each constraint tuple should be 2"); + } + if (!item[0].is_string() || !item[1].is_string()) { + THROW_CODE(InputError, + "The element of each constraint tuple should be string type"); + } + edge_constraints.push_back(std::make_pair(item[0], item[1])); + } + } + auto field_specs = ParseFieldSpecs(args, 3); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + std::unique_ptr options; + if (is_vertex) { + auto vo = std::make_unique(); + vo->primary_field = primary_fd; + options = std::move(vo); + } else { + auto eo = std::make_unique(); + eo->edge_constraints = edge_constraints; + options = std::move(eo); + } + auto ret = ac_db.AddLabel(is_vertex, label, field_specs, *options); + if (!ret) { + throw lgraph::LabelExistException(label, is_vertex); + } +} + +// params: vertex/edge, label +void BuiltinProcedureV2::DbGetLabelSchema(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (args.size() != 2) + THROW_CODE(InputError, + "Wrong number of arguments. This function takes exactly 2 arguments."); + bool is_vertex = ParseIsVertex(args[0].constant.scalar.AsString()); + std::string label = ParseStringArg(args[1], "label_name"); + auto fs = ctx->txn_->GetTxn()->GetSchema(is_vertex, label); + for (auto &f : fs) { + Record r; + r.AddConstant(lgraph::FieldData(f.name)); + r.AddConstant(lgraph::FieldData(lgraph::field_data_helper::FieldTypeName(f.type))); + r.AddConstant(lgraph::FieldData(f.optional)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbGetVertexSchema(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. db.getVertexSchema(label)") + CYPHER_ARG_CHECK(args[0].IsString(), "label type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + const lgraph::Schema *schema = + ctx->txn_->GetTxn()->GetSchema(args[0].constant.scalar.AsString(), true); + if (!schema) { + throw lgraph::CypherException( + FMA_FMT("vertex label {} does not exist", args[0].constant.scalar.AsString())); + } + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(schema).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbGetEdgeSchema(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. db.getEdgeSchema(label)"); + CYPHER_ARG_CHECK(args[0].IsString(), "label type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + const lgraph::Schema *schema = + ctx->txn_->GetTxn()->GetSchema(args[0].constant.scalar.AsString(), false); + if (!schema) { + throw lgraph::CypherException( + FMA_FMT("edge label {} does not exist", args[0].constant.scalar.AsString())); + } + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(schema).serialize())); + records->emplace_back(r.Snapshot()); +} + +// params: vertex/edge, label +void BuiltinProcedureV2::DbDeleteLabel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. db.deleteLabel(label_type, label_name)"); + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + bool is_vertex = ParseIsVertex(args[0].constant.scalar.AsString()); + std::string label = ParseStringArg(args[1], "label_name"); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + size_t affected = 0; + auto ret = ac_db.DeleteLabel(is_vertex, label, &affected); + if (!ret) { + throw lgraph::LabelNotExistException(label); + } +} + +// params: vertex/edge, label, field_names +void BuiltinProcedureV2::DbAlterLabelDelFields(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + if (args.size() != 3) + THROW_CODE(InputError, + "Wrong number of arguments. This function takes exactly 3 arguments."); + bool is_vertex = ParseIsVertex(args[0].constant.scalar.AsString()); + std::string label = ParseStringArg(args[1], "label_name"); + std::vector fields = ParseStringList(args[2], "field_names"); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + size_t affected = 0; + auto ret = ac_db.AlterLabelDelFields(label, fields, is_vertex, &affected); + if (ret) { + Record r; + r.AddConstant(lgraph::FieldData::Int64(static_cast(affected))); + records->emplace_back(r.Snapshot()); + } else { + throw lgraph::LabelNotExistException(label); + } +} + +// params: vertex/edge, label, [field_spec_value_1], [field_spec_value_2]... +void BuiltinProcedureV2::DbAlterLabelAddFields(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + using namespace parser; + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + if (args.size() < 3) + THROW_CODE(InputError, "Too few arguments. This function takes 3 or more arguments."); + bool is_vertex = ParseIsVertex(args[0].constant.scalar.AsString()); + std::string label = ParseStringArg(args[1], "label_name"); + // get field_spec_value + std::vector fields; + std::vector values; + for (size_t i = 2; i < args.size(); i++) { + CYPHER_ARG_CHECK( + args[i].IsArray() && args[i].constant.array->size() == 4, + "Each FieldSpec must be a list of ('name', 'type', default_value, 'optional')"); + const auto &list = *args[i].constant.array; + CYPHER_ARG_CHECK(list[0].IsString() && list[1].IsString() && list[3].IsBool(), + "Each FieldSpec must be a list of (name, type, default_value ,optional)"); + const std::string &name = list[0].AsString(); + lgraph::FieldType ft; + if (!lgraph::field_data_helper::TryGetFieldType(list[1].AsString(), ft)) + THROW_CODE(InputError, "Illegal field type:{}", list[1]); + lgraph::FieldData default_value = list[2]; + fields.emplace_back(name, ft, list[3].AsBool()); + values.emplace_back(std::move(default_value)); + } + // now alter label + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + size_t affected = 0; + auto ret = ac_db.AlterLabelAddFields(label, fields, values, is_vertex, &affected); + if (ret) { + Record r; + r.AddConstant(lgraph::FieldData::Int64(static_cast(affected))); + records->emplace_back(r.Snapshot()); + } else { + throw lgraph::LabelNotExistException(label); + } +} + +// params: vertex/edge, label, [field_spec_1], [field_spec_2],... +void BuiltinProcedureV2::DbAlterLabelModFields(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + if (args.size() < 3) + THROW_CODE(InputError, + "Wrong number of arguments. This function takes 3 or more arguments."); + bool is_vertex = ParseIsVertex(args[0].constant.scalar.AsString()); + std::string label = ParseStringArg(args[1], "label_name"); + std::vector fields = ParseFieldSpecs(args, 2); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + size_t affected = 0; + auto ret = ac_db.AlterLabelModFields(label, fields, is_vertex, &affected); + if (ret) { + Record r; + r.AddConstant(lgraph::FieldData::Int64(static_cast(affected))); + records->emplace_back(r.Snapshot()); + } else { + throw lgraph::LabelNotExistException(label); + } +} + +void BuiltinProcedureV2::DbCreateEdgeLabel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() % SPEC_MEMBER_SIZE_V2 == 2, + "e.g. db.createEdgeLabel(label_name, extra, field_name, field_type, is_optional)") + std::string label; + std::vector fds; + std::vector> edge_constraints; + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + std::string extra; + _ExtractFds(args, label, extra, fds); + auto ec = nlohmann::json::parse(extra); + for (auto &item : ec) { + edge_constraints.push_back(std::make_pair(item[0], item[1])); + } + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + auto ret = ac_db.AddLabel(false, label, fds, lgraph::EdgeOptions(edge_constraints)); + if (!ret) { + throw lgraph::LabelExistException(label, true); + } +} + +void BuiltinProcedureV2::DbAddVertexIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 3, + "need 3 parameters, e.g. db.addIndex(label_name, field_name, unique)") + CYPHER_ARG_CHECK(args[0].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "field_name type should be string") + CYPHER_ARG_CHECK(args[2].IsBool(), "unique type should be boolean") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + auto label = args[0].constant.scalar.AsString(); + auto field = args[1].constant.scalar.AsString(); + auto unique = args[2].constant.scalar.AsBool(); + lgraph::IndexType type = + unique ? lgraph::IndexType::GlobalUniqueIndex : lgraph::IndexType::NonuniqueIndex; + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + bool success = ac_db.AddVertexIndex(label, field, type); + if (!success) { + throw lgraph::IndexExistException(label, field); + } +} + +void BuiltinProcedureV2::DbAddEdgeIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 4, + "need 3 parameters, e.g. " + "db.addEdgeIndex(label_name, field_name, unique, pair_unique)") + CYPHER_ARG_CHECK(args[0].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "field_name type should be string") + CYPHER_ARG_CHECK(args[2].IsBool(), "unique type should be boolean") + CYPHER_ARG_CHECK(args[3].IsBool(), "pair_unique type should be boolean") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + auto label = args[0].constant.scalar.AsString(); + auto field = args[1].constant.scalar.AsString(); + auto unique = args[2].constant.scalar.AsBool(); + auto pair_unique = args[3].constant.scalar.AsBool(); + if (unique && pair_unique) { + THROW_CODE(InputError, "pair_unique and unique configuration cannot occur simultaneously)"); + } + lgraph::IndexType type; + if (unique) { + type = lgraph::IndexType::GlobalUniqueIndex; + } else if (pair_unique) { + type = lgraph::IndexType::PairUniqueIndex; + } else { + type = lgraph::IndexType::NonuniqueIndex; + } + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + bool success = ac_db.AddEdgeIndex(label, field, type); + if (!success) { + throw lgraph::IndexExistException(label, field); + } +} + +void BuiltinProcedureV2::DbAddFullTextIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() == 3, + "need 3 parameters, e.g. db.addFullTextIndex(is_vertex, label_name, field_name)") + CYPHER_ARG_CHECK(args[0].IsBool(), "is_vertex type should be boolean") + CYPHER_ARG_CHECK(args[1].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[2].IsString(), "field_name type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + auto is_vertex = args[0].constant.scalar.AsBool(); + auto label = args[1].constant.scalar.AsString(); + auto field = args[2].constant.scalar.AsString(); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + bool success = ac_db.AddFullTextIndex(is_vertex, label, field); + if (!success) { + throw lgraph::FullTextIndexExistException(label, field); + } +} + +void BuiltinProcedureV2::DbDeleteFullTextIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() == 3, + "need 3 parameters, e.g. db.deleteFullTextIndex(is_vertex, label_name, field_name)"); + + CYPHER_ARG_CHECK(args[0].IsBool(), "is_vertex type should be boolean") + CYPHER_ARG_CHECK(args[1].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[2].IsString(), "field_name type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + bool success = + db.DeleteFullTextIndex(args[0].constant.scalar.AsBool(), args[1].constant.scalar.AsString(), + args[2].constant.scalar.AsString()); + if (!success) { + throw lgraph::FullTextIndexNotExistException(args[1].constant.scalar.AsString(), + args[2].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbRebuildFullTextIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need 2 parameters, e.g. db.rebuildFullTextIndex(vertex_labels, edge_labels)"); + CYPHER_ARG_CHECK(args[0].IsString(), "vertex_labels should be a json array string") + CYPHER_ARG_CHECK(args[1].IsString(), "edge_labels should be a json array string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + std::set v_labels, e_labels; + auto vs = nlohmann::json::parse(args[0].constant.scalar.AsString()); + if (!vs.is_array()) { + THROW_CODE(InputError, "vertex_labels should be a json array string"); + } + for (auto &item : vs) { + v_labels.emplace(item); + } + auto es = nlohmann::json::parse(args[1].constant.scalar.AsString()); + if (!es.is_array()) { + THROW_CODE(InputError, "edge_labels should be a json array string"); + } + for (auto &item : es) { + e_labels.emplace(item); + } + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + db.RebuildFullTextIndex(v_labels, e_labels); +} + +void BuiltinProcedureV2::DbFullTextIndexes(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.FullTextIndexes()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + const auto &ft_indexs = ctx->txn_->GetTxn()->ListFullTextIndexes(); + for (const auto &ft_index : ft_indexs) { + Record r; + r.AddConstant(lgraph::FieldData(std::get<0>(ft_index))); + r.AddConstant(lgraph::FieldData(std::get<1>(ft_index))); + r.AddConstant(lgraph::FieldData(std::get<2>(ft_index))); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbClearEdgeConstraints(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, + "need 1 parameters, e.g. db.clearEdgeConstraints(label_name)") + CYPHER_ARG_CHECK(args[0].IsString(), "label_name type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + auto label = args[0].constant.scalar.AsString(); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + ac_db.ClearEdgeConstraints(label); +} + +void BuiltinProcedureV2::DbAddEdgeConstraints(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need 2 parameters, e.g. db.addEdgeConstraints(label_name, constraints)") + CYPHER_ARG_CHECK(args[0].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "constraints type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + auto label = args[0].constant.scalar.AsString(); + auto constraints = args[1].constant.scalar.AsString(); + std::vector> edge_constraints; + auto ec = nlohmann::json::parse(constraints); + for (auto &item : ec) { + edge_constraints.emplace_back(item[0], item[1]); + } + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + ac_db.AddEdgeConstraints(label, edge_constraints); +} + +void BuiltinProcedureV2::DbmsMetaCountDetail(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.meta.countDetail()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + const auto &counts = ctx->txn_->GetTxn()->countDetail(); + for (const auto &count : counts) { + Record r; + r.AddConstant(lgraph::FieldData(std::get<0>(count))); + r.AddConstant(lgraph::FieldData(std::get<1>(count))); + r.AddConstant(lgraph::FieldData(std::get<2>(count))); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsMetaCount(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.meta.count()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + const auto &counts = ctx->txn_->GetTxn()->countDetail(); + int64_t vertex_num = 0; + int64_t edge_num = 0; + for (const auto &count : counts) { + if (std::get<0>(count)) { + vertex_num += std::get<2>(count); + } else { + edge_num += std::get<2>(count); + } + } + { + Record r; + r.AddConstant(lgraph::FieldData("vertex")); + r.AddConstant(lgraph::FieldData(vertex_num)); + records->emplace_back(r.Snapshot()); + } + { + Record r; + r.AddConstant(lgraph::FieldData("edge")); + r.AddConstant(lgraph::FieldData(edge_num)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsMetaRefreshCount(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.meta.refreshCount()", + args.size())) + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + ac_db.RefreshCount(); +} + +void BuiltinProcedureV2::DbmsSecurityChangePassword(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() == 2, + "need 2 parameters, e.g. dbms.security.changePassword(current_password, new_password)") + CYPHER_ARG_CHECK(args[0].IsString(), "current_password type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "new_password type should be string") + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->ChangeCurrentPassword( + ctx->user_, args[0].constant.scalar.AsString(), args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::UserNotExistException(ctx->user_); + } +} + +void BuiltinProcedureV2::DbmsSecurityChangeUserPassword(RTContext *ctx, + const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() == 2, + "need 2 parameters, e.g. dbms.security.changeUserPassword(user_name, new_password)") + CYPHER_ARG_CHECK(args[0].IsString(), "user_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "new_password type should be string") + + bool success = ctx->galaxy_->ChangeUserPassword(ctx->user_, args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecuritySetUserMemoryLimit(RTContext *ctx, + const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK( + args.size() == 2, + "need 2 parameters, e.g. dbms.security.setUserMemoryLimit(user_name, memory_limit)") + CYPHER_ARG_CHECK(args[0].IsString(), "user_name should be string") + CYPHER_ARG_CHECK(args[1].IsInteger(), "User_Memory_Limit must be an integer"); + + bool success = ctx->galaxy_->SetUserMemoryLimit(ctx->user_, args[0].constant.scalar.AsString(), + args[1].constant.scalar.integer()); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityCreateUser(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need 2 parameters, e.g. dbms.security.createUser(user_name, password)") + CYPHER_ARG_CHECK(args[0].IsString(), "user_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "password type should be string") + bool success = ctx->galaxy_->CreateUser( + ctx->user_, args[0].constant.scalar.AsString(), args[1].constant.scalar.AsString(), + args.size() == 2 ? "" : args[2].constant.scalar.AsString()); + if (!success) { + throw lgraph::UserExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityDeleteUser(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, + "need 1 parameters, e.g. dbms.security.deleteUser(user_name)") + CYPHER_ARG_CHECK(args[0].IsString(), "user_name type should be string") + bool success = ctx->galaxy_->DeleteUser(ctx->user_, args[0].constant.scalar.AsString()); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityListUsers(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.security.listUsers()", + args.size())) + std::map us = ctx->galaxy_->ListUsers(ctx->user_); + for (auto &u : us) { + Record r; + r.AddConstant(lgraph::FieldData(u.first)); + r.AddConstant(lgraph::FieldData(ValueToJson(u.second).serialize())); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsSecurityShowCurrentUser(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.security.showCurrentUser()", + args.size())) + Record r; + r.AddConstant(lgraph::FieldData(ctx->user_)); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityHostWhitelistList(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.security.listAllowedHosts()", + args.size())) + for (auto &ip : ctx->galaxy_->GetIpWhiteList(ctx->user_)) { + Record r; + r.AddConstant(lgraph::FieldData(ip)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsSecurityHostWhitelistAdd(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(!args.empty(), "This function takes one or more string arguments.") + + std::vector ips; + butil::ip_t my_ip; + for (auto &ip : args) { + CYPHER_ARG_CHECK(ip.IsString(), "Host names must be strings.") + CYPHER_ARG_CHECK(butil::str2ip(ip.constant.scalar.AsString().c_str(), &my_ip) == 0, + "Invalid host"); + ips.push_back(ip.constant.scalar.AsString()); + } + Record r; + r.AddConstant(lgraph::FieldData((int64_t)ctx->galaxy_->AddIpsToWhitelist(ctx->user_, ips))); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityHostWhitelistDelete(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(!args.empty(), "This function takes one or more string arguments.") + + std::vector ips; + for (auto &ip : args) { + CYPHER_ARG_CHECK(ip.IsString(), "Host names must be strings.") + ips.push_back(ip.constant.scalar.AsString()); + } + Record r; + r.AddConstant( + lgraph::FieldData((int64_t)ctx->galaxy_->RemoveIpsFromWhitelist(ctx->user_, ips))); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsGraphCreateGraph(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() >= 1, "This function takes one or more arguments"); + CYPHER_ARG_CHECK(args[0].IsString(), "graph_name must be string"); + + /* close the previous txn first, in case of nested transaction */ + if (ctx->txn_) ctx->txn_->Abort(); + lgraph::DBConfig config; + if (args.size() >= 2) { + CYPHER_ARG_CHECK(args[1].IsString(), "description gmust be string"); + config.desc = args[1].constant.scalar.AsString(); + } + if (args.size() >= 3) { + CYPHER_ARG_CHECK(args[2].IsInteger(), "Max_size_GB must be an integer"); + config.db_size = ((size_t)args[2].constant.scalar.integer()) << 30; + } + bool success = + ctx->galaxy_->CreateGraph(ctx->user_, args[0].constant.scalar.AsString(), config); + if (!success) { + throw lgraph::GraphExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsGraphModGraph(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + // CYPHER_ARG_CHECK( + // args.size() == 2, + // "This function takes exactly 2 arguments. e.g. dbms.graph.modGraph(graph_name,config)"); + // CYPHER_ARG_CHECK(args[0].IsString(), "graph_name must be string"); + // /* close the previous txn first, in case of nested transaction */ + // if (ctx->txn_) ctx->txn_->Abort(); + // lgraph::DBConfig config; + // CYPHER_ARG_CHECK(args[1].type == parser::Expression::MAP, "Illega must be map"); + // lgraph::GraphManager::ModGraphActions act; + // act.mod_size = false; + // act.mod_desc = false; + // for (auto &kv : args[1].Map()) { + // if (kv.first == "max_size_GB") { + // act.mod_size = true; + // if (kv.second.type != parser::Expression::INT) + // THROW_CODE(InputError, "Invalid value for max_size_GB: must be integer"); + // act.max_size = kv.second.constant.scalar.integer() << 30; + // } else if (kv.first == "description") { + // act.mod_desc = true; + // if (kv.second.type != parser::Expression::STRING) + // THROW_CODE(InputError, "Invalid value for description: must be string"); + // act.desc = kv.second.constant.scalar.AsString(); + // } else { + // THROW_CODE(InputError, "Invalid config key: " + kv.first); + // } + // } + // bool success = ctx->galaxy_->ModGraph(ctx->user_, args[0].constant.scalar.AsString(), act); + // if (!success) { + // throw lgraph::GraphNotExistException(args[0].constant.scalar.AsString()); + // } +} + +void BuiltinProcedureV2::DbmsGraphDeleteGraph(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (ctx->txn_) ctx->txn_->Abort(); + CYPHER_ARG_CHECK( + args.size() == 1, + "This function takes exactly 1 arguments. e.g. dbms.graph.deleteGraph(graph_name)") + CYPHER_ARG_CHECK(args[0].IsString(), "graph_name must be string") + + /* close the previous txn first, in case of nested transaction */ + bool success = ctx->galaxy_->DeleteGraph(ctx->user_, args[0].constant.scalar.AsString()); + if (!success) { + throw lgraph::GraphNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsGraphListGraphs(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (ctx->txn_) ctx->txn_->Abort(); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.graph.listGraphs()", + args.size())) + auto graphs = ctx->galaxy_->ListGraphs(ctx->user_); + for (auto &g : graphs) { + Record r; + r.AddConstant(lgraph::FieldData(g.first)); + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(g.second).serialize())); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsGraphListUserGraphs(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (ctx->txn_) ctx->txn_->Abort(); + CYPHER_ARG_CHECK(args.size() == 1, FMA_FMT("Function requires 1 arguments, but {} are " + "given. Usage: dbms.graph.listUserGraphs(user_name)", + args.size())) + std::string user_name = args[0].constant.scalar.AsString(); + if ((ctx->user_ != user_name) && !ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + const std::map &graphs = ctx->galaxy_->ListGraphsInternal(); + std::map userGraphs; + for (auto graph : graphs) { + lgraph_api::AccessLevel acl = ctx->galaxy_->GetAcl(ctx->user_, user_name, graph.first); + if (acl == lgraph_api::AccessLevel::NONE) { + continue; + } + userGraphs.emplace(graph.first, graph.second); + } + for (auto &g : userGraphs) { + Record r; + r.AddConstant(lgraph::FieldData(g.first)); + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(g.second).serialize())); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsGraphGetGraphInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (ctx->txn_) ctx->txn_->Abort(); + CYPHER_ARG_CHECK(args.size() == 1, FMA_FMT("This function takes exactly 1 arguments, but {} " + "given. Usage: dbms.graph.getGraphInfo(graph_name)", + args.size())) + + auto graph_ref = ctx->galaxy_->OpenGraph(ctx->user_, args[0].constant.scalar.AsString()); + const lgraph::DBConfig &conf = graph_ref.GetLightningGraph()->GetConfig(); + Record r; + r.AddConstant(lgraph::FieldData(args[0].constant.scalar.AsString())); + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(conf).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSystemInfo(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (ctx->txn_) ctx->txn_->Abort(); + std::string version; + version.append(std::to_string(lgraph::_detail::VER_MAJOR)) + .append(".") + .append(std::to_string(lgraph::_detail::VER_MINOR)) + .append(".") + .append(std::to_string(lgraph::_detail::VER_PATCH)); + std::vector> info = { + {lgraph::RestStrings::VER, lgraph::FieldData(version)}, + {lgraph::RestStrings::UP_TIME, + lgraph::FieldData(ctx->sm_ ? ctx->sm_->GetUpTimeInSeconds() : 0.0)}, + {lgraph::RestStrings::BRANCH, lgraph::FieldData(GIT_BRANCH)}, + {lgraph::RestStrings::COMMIT, lgraph::FieldData(GIT_COMMIT_HASH)}, + {lgraph::RestStrings::WEB_COMMIT, lgraph::FieldData(WEB_GIT_COMMIT_HASH)}, + {lgraph::RestStrings::CPP_ID, lgraph::FieldData(CXX_COMPILER_ID)}, + {lgraph::RestStrings::CPP_VERSION, lgraph::FieldData(CXX_COMPILER_VERSION)}, + {lgraph::RestStrings::PYTHON_VERSION, lgraph::FieldData(PYTHON_LIB_VERSION)}, + }; + for (auto &i : info) { + Record r; + r.AddConstant(lgraph::FieldData(i.first)); + r.AddConstant(i.second); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsConfigList(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (ctx->txn_) ctx->txn_->Abort(); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.config.list()", + args.size())) + const std::shared_ptr gc = ctx->galaxy_->GetGlobalConfigPtr(); + if (!gc) return; + for (auto &kv : gc->ToFieldDataMap()) { + Record r; + r.AddConstant(lgraph::FieldData(kv.first)); + r.AddConstant(kv.second); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsConfigUpdate(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + // ctx->txn_.reset(); + // ctx->ac_db_.reset(); + // CYPHER_ARG_CHECK(args.size() == 1, + // "need exactly one parameter. " + // "e.g. dbms.config.update({durable: false, enable_audit_log: false})") + // CYPHER_ARG_CHECK(args[0].type == parser::Expression::MAP, "role type should be map") + // std::map kvs; + // for (auto &kv : args[0].Map()) { + // kvs[kv.first] = parser::MakeFieldData(kv.second); + // } + // bool need_reload = ctx->galaxy_->UpdateConfig(ctx->user_, kvs); + // // restart galaxy in a separate thread + // if (need_reload) ctx->galaxy_->ReloadFromDisk(); +} + +void BuiltinProcedureV2::DbmsListBackupLogFiles(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.listBackupFiles()", + args.size())) + if (!ctx->sm_) THROW_CODE(InputError, "Cannot be called in embedded mode."); + for (auto &f : ctx->sm_->ListBackupLogFiles()) { + Record r; + r.AddConstant(lgraph::FieldData(f)); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsTakeSnapshot(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.takeSnapshot()", + args.size())) + if (!ctx->sm_) THROW_CODE(InputError, "Cannot be called in embedded mode."); + std::string path = ctx->sm_->TakeSnapshot(); + Record r; + r.AddConstant(lgraph::FieldData(path)); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityListRoles(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.security.listRoles()", + args.size())) + if (ctx->txn_) ctx->txn_->Abort(); + std::map rs = ctx->galaxy_->ListRoles(ctx->user_); + for (auto &u : rs) { + Record r; + r.AddConstant(lgraph::FieldData(u.first)); + auto &table = u.second.graph_access; + auto it = table.begin(); + while (it != table.end()) { + if (it->first == lgraph::_detail::META_GRAPH) + table.erase(it++); + else + ++it; + } + r.AddConstant(lgraph::FieldData(ValueToJson(u.second).serialize())); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbmsSecurityCreateRole(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.createRole(role, desc)"); + CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string"); + CYPHER_ARG_CHECK(args[1].IsString(), "desc type should be string"); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->CreateRole(ctx->user_, args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::RoleExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityDeleteRole(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. dbms.security.deleteRole(role)"); + CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string"); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->DeleteRole(ctx->user_, args[0].constant.scalar.AsString()); + if (!success) { + throw lgraph::RoleNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityGetUserInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. dbms.security.getUserInfo(user)"); + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string"); + if (ctx->txn_) ctx->txn_->Abort(); + auto uinfo = ctx->galaxy_->GetUserInfo(ctx->user_, args[0].constant.scalar.AsString()); + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(uinfo).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityGetUserPermissions(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 1, + "need one parameters, e.g. dbms.security.getUserPermissions(user_name)"); + CYPHER_ARG_CHECK(args[0].IsString(), "user_name type should be string"); + auto uinfo = ctx->galaxy_->ListUserGraphs(ctx->user_, args[0].constant.scalar.AsString()); + if (ctx->txn_) ctx->txn_->Abort(); + Record r; + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(uinfo).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityGetUserMemoryUsage(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. dbms.security.getUserInfo(user)"); + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string"); + if (ctx->txn_) ctx->txn_->Abort(); + int64_t usage = AllocatorManager.GetMemoryUsage(ctx->user_); + Record r; + r.AddConstant(lgraph::FieldData(usage)); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityGetRoleInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. dbms.security.getRoleInfo(role)"); + CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string"); + auto rinfo = ctx->galaxy_->GetRoleInfo(ctx->user_, args[0].constant.scalar.AsString()); + if (ctx->txn_) ctx->txn_->Abort(); + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(rinfo).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsSecurityDisableRole(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.disableRole(role, disable)") + CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string") + CYPHER_ARG_CHECK(args[1].IsBool(), "disable type should be boolean") + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->ModRoleDisable(args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsBool()); + if (!success) { + throw lgraph::RoleNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityModRoleDesc(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.modRoleDesc(role, description)") + CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "description type should be string") + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->ModRoleDesc(args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::RoleNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityRebuildRoleAccessLevel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + // if (!ctx->galaxy_->IsAdmin(ctx->user_)) + // THROW_CODE(Unauthorized, "Admin access right required."); + // CYPHER_ARG_CHECK( + // args.size() == 2, + // "need two parameters, e.g. dbms.security.modAllRoleAccessLevel(role, access_level)") + // CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string") + // CYPHER_ARG_CHECK(args[1].type == parser::Expression::MAP, + // "access_level type should be map, key and val both string") + // std::string role; + // std::unordered_map levels; + // _ExtractAccessLevel(args, role, levels); + // if (ctx->txn_) ctx->txn_->Abort(); + // bool success = ctx->galaxy_->ModAllRoleAccessLevel(role, levels); + // if (!success) { + // throw lgraph::RoleNotExistException(args[0].constant.scalar.AsString()); + // } +} + +void BuiltinProcedureV2::DbmsSecurityModRoleAccessLevel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + // if (!ctx->galaxy_->IsAdmin(ctx->user_)) + // THROW_CODE(Unauthorized, "Admin access right required."); + // CYPHER_ARG_CHECK( + // args.size() == 2, + // "need two parameters, e.g. dbms.security.modRoleAccessLevel(role, access_level)") + // CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string") + // CYPHER_ARG_CHECK(args[1].type == parser::Expression::MAP, + // "access_level type should be map, key and val both string") + // std::string role; + // std::unordered_map levels; + // _ExtractAccessLevel(args, role, levels); + // if (ctx->txn_) ctx->txn_->Abort(); + // bool success = ctx->galaxy_->ModRoleAccessLevel(role, levels); + // if (!success) { + // throw lgraph::RoleNotExistException(args[0].constant.scalar.AsString()); + // } +} + +void BuiltinProcedureV2::DbmsSecurityModRoleFieldAccessLevel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 6, + "need five parameters, " + "e.g. dbms.security.modRoleFieldAccessLevel" + "(role, graph, label, field, label_type, field_access_level)") + CYPHER_ARG_CHECK(args[0].IsString(), "role type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "graph type should be string") + CYPHER_ARG_CHECK(args[2].IsString(), "label type should be string") + CYPHER_ARG_CHECK(args[3].IsString(), "field type should be string") + CYPHER_ARG_CHECK(args[4].IsString(), "label_type type should be string") + CYPHER_ARG_CHECK(args[5].IsString(), "field_access_level type should be string") + cypher::VEC_STR_V2 titles = + ProcedureTitlesV2("dbms.security.modRoleFieldAccessLevel", yield_items); + std::string role = args[0].constant.scalar.AsString(); + std::string graph = args[1].constant.scalar.AsString(); + std::string label = args[2].constant.scalar.AsString(); + std::string field = args[3].constant.scalar.AsString(); + std::string label_type = args[4].constant.scalar.AsString(); + std::string field_access_level = args[5].constant.scalar.AsString(); + // is_vertex + bool is_vertex = true; + if (label_type == "VERTEX" || label_type == "vertex") + is_vertex = true; + else if (label_type == "EDGE" || label_type == "edge") + is_vertex = false; + else + CYPHER_ARG_CHECK(false, "label_type should be VERTEX or EDGE."); + // field_access_level + auto it = ValidFieldAccessLevels.find(field_access_level); + CYPHER_ARG_CHECK(it != ValidFieldAccessLevels.end(), "unknown access level"); + auto level = it->second; + lgraph::AclManager::FieldAccessTable acs_table; + lgraph::AclManager::FieldAccess acs; + acs[lgraph::AclManager::LabelFieldSpec(is_vertex, label, field)] = level; + acs_table[graph] = acs; + if (ctx->txn_) ctx->txn_->Abort(); + if (!ctx->galaxy_->ModRoleFieldAccessLevel(role, acs_table)) + throw lgraph::RoleNotExistException(role); +} + +void BuiltinProcedureV2::DbmsSecurityDisableUser(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.disableUser(user, disable)"); + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string"); + CYPHER_ARG_CHECK(args[1].IsBool(), "disable type should be boolean"); + std::string modified_user = args[0].constant.scalar.AsString(); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = + ctx->galaxy_->ModUserDisable(ctx->user_, modified_user, args[1].constant.scalar.AsBool()); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecuritySetCurrentDesc(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, + "need one parameters, e.g. dbms.security.setCurrentDesc(description)") + CYPHER_ARG_CHECK(args[0].IsString(), "description type should be string") + + std::string modified_user = args[0].constant.scalar.AsString(); + if (modified_user != ctx->user_ && !ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Non-admin user cannot modify other users."); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->SetUserDescription(ctx->user_, ctx->user_, + args[0].constant.scalar.AsString()); + if (!success) { + throw lgraph::UserNotExistException(ctx->user_); + } +} + +void BuiltinProcedureV2::DbmsSecuritySetUserDesc(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.setUserDesc(user, description)") + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "description type should be string") + + std::string modified_user = args[0].constant.scalar.AsString(); + if (modified_user != ctx->user_ && !ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Non-admin user cannot modify other users."); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->galaxy_->SetUserDescription(ctx->user_, args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityDeleteUserRoles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.deleteUserRoles(user, roles)") + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string") + CYPHER_ARG_CHECK(args[1].IsArray(), "roles type should be list") + std::vector roles; + for (auto &a : *args[1].constant.array) { + if (_F_UNLIKELY(!a.IsString())) + THROW_CODE(InputError, "Illegal value for roles: must be a string list ."); + roles.push_back(a.AsString()); + } + if (ctx->txn_) ctx->txn_->Abort(); + bool success = + ctx->galaxy_->DeleteUserRoles(ctx->user_, args[0].constant.scalar.AsString(), roles); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityRebuildUserRoles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.rebuildUserRoles(user, roles)") + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string") + CYPHER_ARG_CHECK(args[1].IsArray(), "roles type should be list") + std::vector roles; + for (auto &a : *args[1].constant.array) { + if (_F_UNLIKELY(!a.IsString())) + THROW_CODE(InputError, "Illegal value for roles: must be a string list ."); + roles.push_back(a.AsString()); + } + if (ctx->txn_) ctx->txn_->Abort(); + bool success = + ctx->galaxy_->RebuildUserRoles(ctx->user_, args[0].constant.scalar.AsString(), roles); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbmsSecurityAddUserRoles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. dbms.security.addUserRoles(user, roles)") + CYPHER_ARG_CHECK(args[0].IsString(), "user type should be string") + CYPHER_ARG_CHECK(args[1].IsArray(), "roles type should be list") + std::vector roles; + for (auto &a : *args[1].constant.array) { + if (_F_UNLIKELY(!a.IsString())) + THROW_CODE(InputError, "Illegal value for roles: must be a string list ."); + roles.push_back(a.AsString()); + } + if (ctx->txn_) ctx->txn_->Abort(); + bool success = + ctx->galaxy_->AddUserRoles(ctx->user_, args[0].constant.scalar.AsString(), roles); + if (!success) { + throw lgraph::UserNotExistException(args[0].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbPluginLoadPlugin(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + // CYPHER_ARG_CHECK( + // args.size() == 7, + // "need seven parameters, e.g. db.plugin.loadPlugin(plugin_type," + // "plugin_name, plugin_content, code_type, plugin_description, read_only, version)") + // CYPHER_ARG_CHECK(args[0].IsString(), + // "plugin_type type should be string") + // CYPHER_ARG_CHECK(args[1].IsString(), + // "plugin_name type should be string") + // CYPHER_ARG_CHECK(args[3].IsString(), "code_type type should be string") + // CYPHER_ARG_CHECK(args[4].IsString(), + // "plugin_description type should be string") + // CYPHER_ARG_CHECK(args[5].IsBool(), "read_only type should be boolean") + // CYPHER_ARG_CHECK(args[6].IsString(), "version type should be string") + // CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + // if (ctx->txn_) ctx->txn_->Abort(); + // lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + // auto plugin_type_it = ValidPluginType.find(args[0].constant.scalar.AsString()); + // CYPHER_ARG_CHECK(plugin_type_it != ValidPluginType.end(), + // "unknown plugin_type, one of ('CPP', 'PY')"); + // auto code_type_it = ValidPluginCodeType.find(args[3].constant.scalar.AsString()); + // CYPHER_ARG_CHECK(code_type_it != ValidPluginCodeType.end(), + // "unknown plugin_type, one of ('PY', 'SO', 'CPP', 'ZIP')"); + // bool success = false; + // fma_common::encrypt::Base64 base64; + // if (args[2].IsString()) { + // std::string content = base64.Decode(args[2].constant.scalar.AsString()); + // success = + // db.LoadPlugin(plugin_type_it->second, ctx->user_, args[1].constant.scalar.AsString(), + // std::vector{content}, std::vector{}, + // code_type_it->second, args[4].constant.scalar.AsString(), + // args[5].constant.scalar.AsBool(), args[6].constant.scalar.AsString()); + // } else if (args[2].type == parser::Expression::MAP) { + // std::vector filenames; + // std::vector codes; + // for (auto &kv : args[2].Map()) { + // if (kv.first[0] == '`' && kv.first.back() == '`') { + // filenames.push_back(kv.first.substr(1, kv.first.size() - 2)); + // } else { + // filenames.push_back(kv.first); + // } + // codes.push_back(base64.Decode(kv.second.constant.scalar.AsString())); + // } + // success = + // db.LoadPlugin(plugin_type_it->second, ctx->user_, args[1].constant.scalar.AsString(), + // codes, filenames, + // code_type_it->second, args[4].constant.scalar.AsString(), + // args[5].constant.scalar.AsBool(), args[6].constant.scalar.AsString()); + // } else { + // throw lgraph::ReminderException("plugin_content should be string or map"); + // } + + // if (!success) { + // throw lgraph::PluginExistException(args[1].constant.scalar.AsString()); + // } +} + +void BuiltinProcedureV2::DbPluginDeletePlugin(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. db.plugin.deletePlugin(plugin_type, plugin_name)") + CYPHER_ARG_CHECK(args[0].IsString(), "plugin_type type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "plugin_name type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + auto plugin_type_it = ValidPluginType.find(args[0].constant.scalar.AsString()); + CYPHER_ARG_CHECK(plugin_type_it != ValidPluginType.end(), + "unknown plugin_type, one of ('CPP', 'PY')") + bool success = + db.DelPlugin(plugin_type_it->second, ctx->user_, args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::PluginNotExistException(args[1].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbPluginGetPluginInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK((args.size() == 2 || args.size() == 3), + "need two or three parameters, e.g. db.plugin.getPluginInfo(plugin_type, " + "plugin_name,show_code=false)") + CYPHER_ARG_CHECK(args[0].IsString(), "plugin_type type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "plugin_name type should be string") + bool show_code = false; + if (args.size() == 3) { + CYPHER_ARG_CHECK(args[2].IsBool(), "show_code type should be boolean") + show_code = args[2].constant.scalar.AsBool(); + } + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + auto plugin_type_it = ValidPluginType.find(args[0].constant.scalar.AsString()); + CYPHER_ARG_CHECK(plugin_type_it != ValidPluginType.end(), + "unknown plugin_type, one of ('CPP', 'PY')") + lgraph::PluginCode co; + bool success = db.GetPluginCode(plugin_type_it->second, ctx->user_, + args[1].constant.scalar.AsString(), co); + if (!success) { + throw lgraph::PluginNotExistException(args[1].constant.scalar.AsString()); + } + if (show_code) { + std::string encoded = lgraph_api::base64::Encode(co.code); + co.code = encoded; + } else { + co.code = "Not show code here."; + } + Record r; + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(co).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbPluginListPlugin(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need 2 parameters, e.g. db.plugin.listPlugin(plugin_type, plugin_version)") + CYPHER_ARG_CHECK(args[0].IsString(), "plugin_type type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + auto plugin_type_it = ValidPluginType.find(args[0].constant.scalar.AsString()); + CYPHER_ARG_CHECK(plugin_type_it != ValidPluginType.end(), + "unknown plugin_type, one of ('CPP', 'PY')") + + CYPHER_ARG_CHECK(args[1].IsString(), "plugin_version type should be string") + std::string version = args[1].constant.scalar.AsString(); + CYPHER_ARG_CHECK(version == lgraph::plugin::PLUGIN_VERSION_1 || + version == lgraph::plugin::PLUGIN_VERSION_2 || + version == lgraph::plugin::PLUGIN_VERSION_ANY, + "unknown plugin_version, one of ('V1', 'V2', 'Any')") + + std::vector descs = db.ListPlugins(plugin_type_it->second, ctx->user_); + for (auto &d : descs) { + if (version != lgraph::plugin::PLUGIN_VERSION_ANY && d.version != version) continue; + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(d).serialize())); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbPluginListUserPlugins(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.graph.listUserPlugins()", + args.size())) + std::unordered_map dbs = + ctx->galaxy_->OpenUserGraphs(ctx->user_, ctx->user_); + for (auto &kv : ValidPluginType) { + for (auto &db : dbs) { + std::vector descs = db.second.ListPlugins(kv.second, ctx->user_); + for (auto &d : descs) { + Record r; + r.AddConstant(lgraph::FieldData(db.first)); + r.AddConstant(lgraph::FieldData(ValueToJson(d).serialize())); + records->emplace_back(r.Snapshot()); + } + } + } +} + +void BuiltinProcedureV2::DbPluginCallPlugin(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 5, + "need five parameters, e.g. " + "db.plugin.callPlugin(plugin_type, plugin_name, param, timeout, in_process)") + CYPHER_ARG_CHECK(args[0].IsString(), "plugin_type type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "plugin_name type should be string") + CYPHER_ARG_CHECK(args[2].IsString(), "param type should be string") + CYPHER_ARG_CHECK(args[3].IsReal(), "timeout type should be double") + CYPHER_ARG_CHECK(args[4].IsBool(), "in_process type should be boolean") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + auto plugin_type_it = ValidPluginType.find(args[0].constant.scalar.AsString()); + CYPHER_ARG_CHECK(plugin_type_it != ValidPluginType.end(), + "unknown plugin_type, one of ('CPP', 'PY')") + lgraph::PluginManager::PluginType type = plugin_type_it->second; + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + std::string name = args[1].constant.scalar.AsString(); + lgraph::TimeoutTaskKiller timeout_killer; + if (args[3].constant.scalar.AsDouble() > 0) { + timeout_killer.SetTimeout(args[3].constant.scalar.AsDouble()); + } + std::string res; + if (!db.CallPlugin(ctx->txn_.get(), type, ctx->user_, name, args[2].constant.scalar.AsString(), + args[3].constant.scalar.AsDouble(), args[4].constant.scalar.AsBool(), res)) { + throw lgraph::PluginNotExistException(name); + } + Record r; + r.AddConstant(lgraph::FieldData(res)); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbImportorDataImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 5, + "need five parameters, e.g. db.importor.dataImportor" + "(description, content, continue_on_error, thread_nums, delimiter)") + CYPHER_ARG_CHECK(args[0].IsString(), "description type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "content type should be string") + CYPHER_ARG_CHECK(args[2].IsBool(), "continue_on_error type should be boolean"); + CYPHER_ARG_CHECK(args[3].IsInteger(), "thread_nums type should be integer") + CYPHER_ARG_CHECK(args[4].IsString(), "delimiter type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + if (db.GetAccessLevel() < lgraph::AccessLevel::WRITE) + throw lgraph::CypherException("Need write permission to do import."); + lgraph::import_v2::ImportOnline::Config config; + config.continue_on_error = args[2].constant.scalar.AsBool(); + config.n_threads = args[3].constant.scalar.integer(); + config.delimiter = args[4].constant.scalar.AsString(); + fma_common::encrypt::Base64 base64; + std::string desc = base64.Decode(args[0].constant.scalar.AsString()); + std::string content = base64.Decode(args[1].constant.scalar.AsString()); + std::string log = lgraph::import_v2::ImportOnline::HandleOnlineTextPackage( + std::move(desc), std::move(content), db.GetLightningGraph(), config); +} + +void BuiltinProcedureV2::DbImportorFullImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + // ctx->txn_.reset(); + // ctx->ac_db_.reset(); + // CYPHER_ARG_CHECK(args.size() == 1, + // "need exactly one parameter. " + // "e.g. db.importor.fullImportor({})") + // CYPHER_ARG_CHECK(args[0].type == parser::Expression::MAP, "conf type should be map") + // if (!ctx->galaxy_->IsAdmin(ctx->user_)) + // THROW_CODE(Unauthorized, "Admin access right required."); + + // // parse parameter + // lgraph::import_v3::Importer::Config import_config_v3; + // std::map full_import_conf; + // for (auto &kv : args[0].Map()) { + // full_import_conf[kv.first] = parser::MakeFieldData(kv.second); + // } + // auto check = [&full_import_conf](const std::string& name, lgraph::FieldType type) { + // if (full_import_conf.count(name) && full_import_conf[name].GetType() != type) + // throw lgraph::CypherException("Option " + name + " is not " + to_string(type)); + // return full_import_conf.count(name); + // }; + + // if (!full_import_conf.count("config_file")) + // THROW_CODE(InputError, "Option config_file does not exist."); + // if (!check("graph_name", lgraph::FieldType::STRING)) + // full_import_conf["graph_name"] = + // lgraph::FieldData(lgraph::_detail::DEFAULT_GRAPH_DB_NAME); + // if (!check("delete_if_exists", lgraph::FieldType::BOOL)) + // full_import_conf["delete_if_exists"] = lgraph::FieldData(false); + // if (!check("username", lgraph::FieldType::STRING)) + // full_import_conf["username"] = + // lgraph::FieldData(lgraph::_detail::DEFAULT_ADMIN_NAME); + // if (!full_import_conf["delete_if_exists"].AsBool() && + // ctx->galaxy_->ListGraphsInternal().count( + // full_import_conf["graph_name"].string())) { + // throw lgraph::CypherException("DB exists and cannot be deleted."); + // } + + // std::mutex mu; + // std::condition_variable cv; + // bool ok_to_leave = false; + // std::string data_file_path, log, error; + // std::thread worker([&]() { + // std::lock_guard l(mu); + // try { + // import_config_v3.db_dir = ctx->galaxy_->GetConfig().dir + "/.import_tmp"; + // import_config_v3.graph = lgraph::_detail::DEFAULT_GRAPH_DB_NAME; + // import_config_v3.config_file = full_import_conf["config_file"].string(); + // import_config_v3.user = full_import_conf["username"].string(); + // if (check("password", lgraph::FieldType::STRING)) + // import_config_v3.password = full_import_conf["password"].string(); + // if (check("continue_on_error", lgraph::FieldType::BOOL)) + // import_config_v3.continue_on_error = + // full_import_conf["continue_on_error"].AsBool(); + // if (check("delimiter", lgraph::FieldType::STRING)) + // import_config_v3.delimiter = full_import_conf["delimiter"].string(); + // import_config_v3.delete_if_exists = true; + // if (check("parse_block_size", lgraph::FieldType::INT64)) + // import_config_v3.parse_block_size = + // full_import_conf["parse_block_size"].AsInt64(); + // if (check("parse_block_threads", lgraph::FieldType::INT64)) + // import_config_v3.parse_block_threads = + // full_import_conf["parse_block_threads"].AsInt64(); + // if (check("parse_file_threads", lgraph::FieldType::INT64)) + // import_config_v3.parse_file_threads = + // full_import_conf["parse_file_threads"].AsInt64(); + // if (check("generate_sst_threads", lgraph::FieldType::INT64)) + // import_config_v3.generate_sst_threads = + // full_import_conf["generate_sst_threads"].AsInt64(); + // if (check("read_rocksdb_threads", lgraph::FieldType::INT64)) + // import_config_v3.read_rocksdb_threads = + // full_import_conf["read_rocksdb_threads"].AsInt64(); + // if (check("vid_num_per_reading", lgraph::FieldType::INT64)) + // import_config_v3.vid_num_per_reading = + // full_import_conf["vid_num_per_reading"].AsInt64(); + // if (check("max_size_per_reading", lgraph::FieldType::INT64)) + // import_config_v3.max_size_per_reading = + // full_import_conf["max_size_per_reading"].AsInt64(); + // if (check("compact", lgraph::FieldType::BOOL)) + // import_config_v3.compact = full_import_conf["compact"].AsBool(); + // if (check("keep_vid_in_memory", lgraph::FieldType::BOOL)) + // import_config_v3.keep_vid_in_memory = + // full_import_conf["keep_vid_in_memory"].AsBool(); + // if (check("enable_fulltext_index", lgraph::FieldType::BOOL)) + // import_config_v3.enable_fulltext_index = + // full_import_conf["enable_fulltext_index"].AsBool(); + // if (check("fulltext_index_analyzer", lgraph::FieldType::STRING)) + // import_config_v3.fulltext_index_analyzer = + // full_import_conf["fulltext_index_analyzer"].string(); + // import_config_v3.import_online = true; + // lgraph::import_v3::Importer importer(import_config_v3); + // importer.DoImportOffline(); + // log = importer.OnlineFullImportLog(); + // for (const auto& entry : + // std::filesystem::directory_iterator(import_config_v3.db_dir)) { + // if (entry.is_directory() && entry.path().filename().string() != ".meta" && + // std::filesystem::exists(entry.path().string() + "/data.mdb")) { + // data_file_path = entry.path().string() + "/data.mdb"; + // break; + // } + // } + // } catch (std::exception &e) { + // error = e.what(); + // } + // ok_to_leave = true; + // cv.notify_all(); + // }); + // worker.detach(); + // std::unique_lock l(mu); + // while (!ok_to_leave) cv.wait(l); + // auto& fs = fma_common::FileSystem::GetFileSystem(ctx->galaxy_->GetConfig().dir + + // "/.import_tmp"); + // if (error.empty()) { + // lgraph::DBConfig dbConfig; + // dbConfig.dir = ctx->galaxy_->GetConfig().dir; + // dbConfig.name = full_import_conf["graph_name"].string(); + // dbConfig.create_if_not_exist = true; + // ctx->galaxy_->CreateGraph(full_import_conf["username"].string(), + // full_import_conf["graph_name"].string(), dbConfig, + // data_file_path); + // fs.RemoveDir(ctx->galaxy_->GetConfig().dir + "/.import_tmp"); + // Record r; + // r.AddConstant(lgraph::FieldData(log)); + // records->emplace_back(r.Snapshot()); + // } else { + // fs.RemoveDir(ctx->galaxy_->GetConfig().dir + "/.import_tmp"); + // throw lgraph::CypherException(error); + // } +} + +void BuiltinProcedureV2::DbImportorFullFileImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + ctx->txn_.reset(); + ctx->ac_db_.reset(); + CYPHER_ARG_CHECK((args.size() == 2 || args.size() == 3), + "need no more than three parameters and no less than two parameters. " + "e.g. db.importor.fullFileImportor({\"ha\",\"data.mdb\",[false]})") + CYPHER_ARG_CHECK(args[0].IsString(), "graph_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "path type should be string") + bool remote = false; + if (args.size() == 3) { + CYPHER_ARG_CHECK(args[2].IsBool(), "remote type should be bool") + remote = args[2].constant.scalar.AsBool(); + } + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + std::string graph_name = args[0].constant.scalar.AsString(), + path = args[1].constant.scalar.AsString(); + if (remote) { + std::string outputFilename = ctx->galaxy_->GetConfig().dir + "/.import.file.data.mdb"; + std::string command = "wget -O " + outputFilename + " " + path; + int result = std::system(command.c_str()); + if (result == 0) { + LOG_INFO() << "Downloaded file saved as: " << outputFilename; + } else { + LOG_ERROR() << "Failed to download file"; + throw lgraph::CypherException("Failed to download file"); + } + path = ctx->galaxy_->GetConfig().dir + "/.import.file.data.mdb"; + } + + lgraph::DBConfig dbConfig; + dbConfig.dir = ctx->galaxy_->GetConfig().dir; + dbConfig.name = graph_name; + dbConfig.create_if_not_exist = true; + bool success = ctx->galaxy_->CreateGraph(ctx->user_, graph_name, dbConfig, path); + if (remote) { + auto &fs_download = fma_common::FileSystem::GetFileSystem(ctx->galaxy_->GetConfig().dir + + "/.import.file.data.mdb"); + fs_download.Remove(ctx->galaxy_->GetConfig().dir + "/.import.file.data.mdb"); + } + if (!success) throw lgraph::GraphCreateException(args[0].constant.scalar.AsString()); +} + +void BuiltinProcedureV2::DbImportorSchemaImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 1, + "need one parameters, e.g. db.importor.schemaImportor(description)") + CYPHER_ARG_CHECK(args[0].IsString(), "description type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + + lgraph::AccessControlledDB db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + if (db.GetAccessLevel() < lgraph::AccessLevel::WRITE) + throw lgraph::CypherException("Need write permission to do import."); + fma_common::encrypt::Base64 base64; + std::string desc = base64.Decode(args[0].constant.scalar.AsString()); + std::string log = ::lgraph::import_v2::ImportOnline::HandleOnlineSchema(std::move(desc), db); +} + +void BuiltinProcedureV2::DbDeleteIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. db.deleteIndex(label_name, field_name)") + CYPHER_ARG_CHECK(args[0].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "field_name type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->ac_db_->DeleteVertexIndex(args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::IndexNotExistException(args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbDeleteEdgeIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.size() == 2, + "need two parameters, e.g. db.deleteIndex(label_name, field_name)") + CYPHER_ARG_CHECK(args[0].IsString(), "label_name type should be string") + CYPHER_ARG_CHECK(args[1].IsString(), "field_name type should be string") + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + bool success = ctx->ac_db_->DeleteEdgeIndex(args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + if (!success) { + throw lgraph::IndexNotExistException(args[0].constant.scalar.AsString(), + args[1].constant.scalar.AsString()); + } +} + +void BuiltinProcedureV2::DbFlushDB(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.flushDB()", + args.size())) + ctx->ac_db_->Flush(); +} + +void BuiltinProcedureV2::DbDropDB(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + if (ctx->txn_) ctx->txn_->Abort(); + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.dropDB()", + args.size())) + ctx->ac_db_->DropAllData(); +} + +void BuiltinProcedureV2::DbTaskListTasks(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.task.listTasks()", + args.size())) + if (ctx->txn_) ctx->txn_->Abort(); + std::map rs = ctx->galaxy_->ListRoles(ctx->user_); + + auto tasksInfo = lgraph::TaskTracker::GetInstance().ListRunningTasks(); + for (auto &t : tasksInfo) { + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(t).serialize())); + records->emplace_back(r.Snapshot()); + } +} + +void BuiltinProcedureV2::DbTaskTerminateTask(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + if (!ctx->galaxy_->IsAdmin(ctx->user_)) + THROW_CODE(Unauthorized, "Admin access right required."); + CYPHER_ARG_CHECK(args.size() == 1, "need one parameters, e.g. dbms.task.terminateTask(task_id)") + CYPHER_ARG_CHECK(args[0].IsString(), "task_id type should be string") + lgraph::TaskTracker::TaskId task_id = lgraph::TaskTracker::TaskId(); + task_id.FromString(args[0].constant.scalar.AsString()); + auto r = lgraph::TaskTracker::GetInstance().KillTask(task_id); + switch (r) { + case lgraph::TaskTracker::SUCCESS: + return; + case lgraph::TaskTracker::NOTFOUND: + throw lgraph::TaskNotExistException(args[0].constant.scalar.AsString()); + case lgraph::TaskTracker::FAIL_TO_KILL: + throw lgraph::TaskKilledFailedException(args[0].constant.scalar.AsString()); + default: + return; + } +} + +void BuiltinProcedureV2::DbMonitorServerInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.monitor.serverInfo()", + args.size())) + Record r; + fma_common::HardwareInfo::CPURate cpuRate = fma_common::HardwareInfo::GetCPURate(); + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(cpuRate).serialize())); + + struct fma_common::HardwareInfo::MemoryInfo memoryInfo; + fma_common::HardwareInfo::GetMemoryInfo(memoryInfo); + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(memoryInfo).serialize())); + + fma_common::HardwareInfo::DiskRate diskRate = fma_common::HardwareInfo::GetDiskRate(); + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(diskRate).serialize())); + + struct fma_common::DiskInfo diskInfo; + fma_common::GetDiskInfo(diskInfo, ctx->galaxy_->GetConfig().dir.data()); + r.AddConstant(lgraph::FieldData( + lgraph::ValueToJson(diskInfo, fma_common::GetDirSpace(ctx->galaxy_->GetConfig().dir.data())) + .serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbMonitorTuGraphInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: db.monitor.tuGraphInfo()", + args.size())) + if (!ctx) CYPHER_INTL_ERR(); + Record r; + r.AddConstant(lgraph::FieldData(ValueToJson(ctx->sm_->GetStats()).serialize())); + records->emplace_back(r.Snapshot()); +} + +void BuiltinProcedureV2::DbmsHaClusterInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records) { + CYPHER_ARG_CHECK(args.empty(), FMA_FMT("Function requires 0 arguments, but {} are " + "given. Usage: dbms.ha.clusterInfo()", + args.size())) + if (ctx->txn_) ctx->txn_->Abort(); + if (!ctx->sm_->IsInHaMode()) + THROW_CODE(InputError, "The service should be started as a high availability cluster ."); + auto peers = ctx->sm_->ListPeers(); + Record r; + r.AddConstant(lgraph::FieldData(lgraph::ValueToJson(peers).serialize())); + r.AddConstant(lgraph::FieldData(ctx->sm_->IsCurrentMaster())); + records->emplace_back(r.Snapshot()); +} + +// static void _FetchPath(lgraph::Transaction &txn, size_t hops, +// std::unordered_map &parent, +// std::unordered_map &child, +// lgraph::VertexId vid_from, lgraph::VertexId vid_a, lgraph::VertexId vid_b, +// lgraph::VertexId vid_to, cypher::Path &path) { +// std::vector vids; +// auto vid = vid_a; +// while (vid != vid_from) { +// vids.push_back(vid); +// vid = parent[vid]; +// } +// vids.push_back(vid); +// std::reverse(vids.begin(), vids.end()); +// vid = vid_b; +// while (vid != vid_to) { +// vids.push_back(vid); +// vid = child[vid]; +// } +// vids.push_back(vid); +// if (hops != 0 && vids.size() != hops + 1) { +// throw lgraph::ReminderException("_FetchPath failed"); +// } +// for (size_t i = 0; i < hops; i++) { +// // TODO(any): fake edges! +// path.Append(lgraph::EdgeUid(vids[i], vids[i + 1], 0, 0, 0)); +// } +// } + +// template +// static bool _Filter(lgraph::Transaction &txn, const EIT &eit, +// const EDGE_FILTER_T &edge_filter) { +// for (auto &kv1 : edge_filter) { +// auto field = txn.GetEdgeField(eit.GetUid(), kv1.first); +// for (auto &kv2 : kv1.second) { +// if ((kv2.first == "smaller_than" && field >= kv2.second) || +// (kv2.first == "greater_than" && field <= kv2.second)) { +// return false; +// } +// } +// } +// return true; +// } + +// static std::vector _GetNeighbors(lgraph::Transaction &txn, +// lgraph::VertexId vid, +// const std::string &edge_label, +// const EDGE_FILTER_T& edge_filter, +// const parser::LinkDirection& direction, +// std::optional per_node_limit) { +// auto vit = txn.GetVertexIterator(vid); +// CYPHER_THROW_ASSERT(vit.IsValid()); +// std::vector neighbors; +// if (edge_label.empty()) { +// bool out_edge_left = false, in_edge_left = false; +// neighbors = vit.ListDstVids(nullptr, nullptr, +// per_node_limit.has_value() ? per_node_limit.value() : 10000, +// &out_edge_left, nullptr); +// auto srcIds = vit.ListSrcVids(nullptr, nullptr, +// per_node_limit.has_value() ? per_node_limit.value() : 10000, +// &in_edge_left, nullptr); +// if (out_edge_left || in_edge_left) { +// LOG_WARN() << "Result trimmed down because " << vid +// << " has more than 10000 in/out neighbours"; +// } +// if (direction == parser::LinkDirection::RIGHT_TO_LEFT) { +// neighbors = srcIds; +// } else if (direction == parser::LinkDirection::DIR_NOT_SPECIFIED) { +// neighbors.reserve(neighbors.size() + srcIds.size()); +// neighbors.insert(neighbors.end(), srcIds.begin(), srcIds.end()); +// } +// } else { +// auto edge_lid = txn.GetLabelId(false, edge_label); +// if (direction == parser::LinkDirection::LEFT_TO_RIGHT || +// direction == parser::LinkDirection::DIR_NOT_SPECIFIED) { +// size_t count = 0; +// for (auto eit = vit.GetOutEdgeIterator(lgraph::EdgeUid( +// vid, 0, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// count += 1; +// if (per_node_limit.has_value() && count > per_node_limit.value()) { +// break; +// } +// if (!_Filter(txn, eit, edge_filter)) continue; +// neighbors.push_back(eit.GetDst()); +// } +// } +// if (direction == parser::LinkDirection::RIGHT_TO_LEFT || +// direction == parser::LinkDirection::DIR_NOT_SPECIFIED) { +// size_t count = 0; +// for (auto eit = vit.GetInEdgeIterator(lgraph::EdgeUid(0, vid, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// count += 1; +// if (per_node_limit.has_value() && count > per_node_limit.value()) { +// break; +// } +// if (!_Filter(txn, eit, edge_filter)) continue; +// neighbors.push_back(eit.GetSrc()); +// } +// } +// } +// return neighbors; +// } + +/* All the shortestPath procedures assume that they are being executed on undirected graphs. + * Just like described in neo4j: + * As of the 3.4.7.0 release, all the Shortest Path procedures assume that they are being executed + * on undirected graphs. Therefore, the direction of a relationship can be ignored. If you are + * running these algorithms on a graph where the direction is important, you can use the direction + * parameter. For example, direction:"INCOMING" or direction:"OUTGOING". + */ +// static void _P2PUnweightedShortestPath(lgraph::Transaction &txn, lgraph::VertexId start_vid, +// lgraph::VertexId end_vid, const std::string &edge_label, +// size_t max_hops, cypher::Path &path, +// const EDGE_FILTER_T &edge_filter, +// parser::LinkDirection &dir, +// std::optional per_node_limit) { +// path.Clear(); +// path.SetStart(start_vid); +// if (start_vid == end_vid) return; +// std::unordered_map parent{{start_vid, start_vid}}; +// std::unordered_map child{{end_vid, end_vid}}; +// std::vector forward_q{start_vid}; +// std::vector backward_q{end_vid}; +// size_t hops = 0; +// parser::LinkDirection forward_dir = dir; +// parser::LinkDirection backward_dir = +// dir == parser::LinkDirection::RIGHT_TO_LEFT ? parser::LinkDirection::LEFT_TO_RIGHT +// : dir == parser::LinkDirection::LEFT_TO_RIGHT ? parser::LinkDirection::RIGHT_TO_LEFT +// : parser::LinkDirection::DIR_NOT_SPECIFIED; +// while (hops++ < max_hops) { +// std::vector next_q; +// // decide which way to search first +// if (forward_q.size() <= backward_q.size()) { +// // search forward +// for (auto vid : forward_q) { +// auto nbrs = _GetNeighbors(txn, vid, edge_label, edge_filter, forward_dir, +// per_node_limit); +// for (auto nbr : nbrs) { +// if (child.find(nbr) != child.end()) { +// // found the path +// _FetchPath(txn, hops, parent, child, start_vid, vid, nbr, end_vid, path); +// return; +// } +// auto it = parent.find(nbr); +// if (it == parent.end()) { +// parent.emplace_hint(it, nbr, vid); +// next_q.push_back(nbr); +// } +// } +// } +// if (next_q.empty()) break; +// forward_q = std::move(next_q); +// } else { +// for (auto vid : backward_q) { +// auto nbrs = _GetNeighbors(txn, vid, edge_label, edge_filter, backward_dir, +// per_node_limit); +// for (auto nbr : nbrs) { +// if (parent.find(nbr) != parent.end()) { +// // found the path +// _FetchPath(txn, hops, parent, child, start_vid, nbr, vid, end_vid, path); +// return; +// } +// auto it = child.find(nbr); +// if (it == child.end()) { +// child.emplace_hint(it, nbr, vid); +// next_q.push_back(nbr); +// } +// } +// } +// if (next_q.empty()) break; +// backward_q = std::move(next_q); +// } +// } +// } + +// template +// static void _EmplaceForwardNeighbor( +// const EIT &eit, const int fhop, const std::unordered_map &child, +// std::unordered_map &parent, +// std::vector> &hits, +// std::vector &next_q) { +// lgraph::VertexId vid, nbr; +// bool direction; +// if (std::is_same::value) { +// vid = eit.GetSrc(); +// nbr = eit.GetDst(); +// direction = true; +// } else { +// vid = eit.GetDst(); +// nbr = eit.GetSrc(); +// direction = false; +// } +// if (child.find(nbr) != child.end()) { +// hits.emplace_back(vid, nbr, eit.GetLabelId(), eit.GetEdgeId(), direction); +// } else { +// auto it = parent.find(nbr); +// if (it == parent.end()) { +// parent.emplace_hint(it, nbr, fhop); +// next_q.emplace_back(nbr); +// } +// } +// } + +// template +// static void _EmplaceBackwardNeighbor( +// const EIT &eit, const int bhop, const std::unordered_map &parent, +// std::unordered_map &child, +// std::vector> &hits, +// std::vector &next_q) { +// lgraph::VertexId vid, nbr; +// bool direction; +// if (std::is_same::value) { +// vid = eit.GetSrc(); +// nbr = eit.GetDst(); +// direction = false; +// } else { +// vid = eit.GetDst(); +// nbr = eit.GetSrc(); +// direction = true; +// } +// if (parent.find(nbr) != parent.end()) { +// hits.emplace_back(nbr, vid, eit.GetLabelId(), eit.GetEdgeId(), direction); +// } else { +// auto it = child.find(nbr); +// if (it == child.end()) { +// child.emplace_hint(it, nbr, bhop); +// next_q.emplace_back(nbr); +// } +// } +// } + +// void _EnumeratePartialPaths(lgraph::Transaction &txn, +// const std::unordered_map &hop_info, const int64_t vid, +// const int depth, const std::string &edge_label, cypher::Path &path, +// std::vector &paths) { +// if (depth != 0) { +// if (edge_label.empty()) { +// for (auto eit = txn.GetOutEdgeIterator(vid); eit.IsValid(); eit.Next()) { +// int64_t nbr = eit.GetDst(); +// auto it = hop_info.find(nbr); +// if (it != hop_info.end() && it->second == depth - 1) { +// path.Append(eit.GetUid()); +// _EnumeratePartialPaths(txn, hop_info, nbr, depth - 1, +// edge_label, path, paths); +// path.PopBack(); +// } +// } +// for (auto eit = txn.GetInEdgeIterator(vid); eit.IsValid(); eit.Next()) { +// int64_t nbr = eit.GetSrc(); +// auto it = hop_info.find(nbr); +// if (it != hop_info.end() && it->second == depth - 1) { +// path.Append(eit.GetUid()); +// _EnumeratePartialPaths(txn, hop_info, nbr, depth - 1, +// edge_label, path, paths); +// path.PopBack(); +// } +// } +// } else { +// auto edge_lid = txn.GetLabelId(false, edge_label); +// for (auto eit = txn.GetOutEdgeIterator(lgraph::EdgeUid( +// vid, 0, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// int64_t nbr = eit.GetDst(); +// auto it = hop_info.find(nbr); +// if (it != hop_info.end() && it->second == depth - 1) { +// path.Append(eit.GetUid()); +// _EnumeratePartialPaths(txn, hop_info, nbr, depth - 1, +// edge_label, path, paths); +// path.PopBack(); +// } +// } +// for (auto eit = txn.GetInEdgeIterator(lgraph::EdgeUid(0, vid, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// int64_t nbr = eit.GetSrc(); +// auto it = hop_info.find(nbr); +// if (it != hop_info.end() && it->second == depth - 1) { +// path.Append(eit.GetUid()); +// _EnumeratePartialPaths(txn, hop_info, nbr, depth - 1, +// edge_label, path, paths); +// path.PopBack(); +// } +// } +// } +// } else { +// paths.emplace_back(path); +// } +// } + +// static void _P2PUnweightedAllShortestPaths(lgraph::Transaction &txn, lgraph::VertexId start_vid, +// lgraph::VertexId end_vid, const std::string &edge_label, +// std::vector &paths) { +// // TODO(heng): fix PrimaryId +// if (start_vid == end_vid) { +// paths.emplace_back(cypher::Path()); +// paths.back().SetStart(start_vid); +// return; +// } +// std::unordered_map parent{{start_vid, 0}}; +// std::unordered_map child{{end_vid, 0}}; +// std::vector forward_q{start_vid}; +// std::vector backward_q{end_vid}; +// int fhop = 0; +// int bhop = 0; +// // +// std::vector< +// std::tuple> +// hits; +// for (int hop = 0; !forward_q.empty() && !backward_q.empty() && hits.empty(); hop++) { +// std::vector next_q; +// if (forward_q.size() <= backward_q.size()) { +// fhop++; +// for (auto vid : forward_q) { +// if (edge_label.empty()) { +// for (auto eit = txn.GetOutEdgeIterator(vid); eit.IsValid(); eit.Next()) { +// _EmplaceForwardNeighbor(eit, fhop, child, parent, hits, next_q); +// } +// for (auto eit = txn.GetInEdgeIterator(vid); eit.IsValid(); eit.Next()) { +// _EmplaceForwardNeighbor(eit, fhop, child, parent, hits, next_q); +// } +// } else { +// auto edge_lid = txn.GetLabelId(false, edge_label); +// for (auto eit = +// txn.GetOutEdgeIterator(lgraph::EdgeUid(vid, 0, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// _EmplaceForwardNeighbor(eit, fhop, child, parent, hits, next_q); +// } +// for (auto eit = +// txn.GetInEdgeIterator(lgraph::EdgeUid(0, vid, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// _EmplaceForwardNeighbor(eit, fhop, child, parent, hits, next_q); +// } +// } +// } +// std::sort(next_q.begin(), next_q.end()); +// forward_q.swap(next_q); +// } else { +// bhop++; +// for (auto vid : backward_q) { +// if (edge_label.empty()) { +// for (auto eit = txn.GetOutEdgeIterator(vid); eit.IsValid(); eit.Next()) { +// _EmplaceBackwardNeighbor(eit, bhop, parent, child, hits, next_q); +// } +// for (auto eit = txn.GetInEdgeIterator(vid); eit.IsValid(); eit.Next()) { +// _EmplaceBackwardNeighbor(eit, bhop, parent, child, hits, next_q); +// } +// } else { +// auto edge_lid = txn.GetLabelId(false, edge_label); +// for (auto eit = +// txn.GetOutEdgeIterator(lgraph::EdgeUid(vid, 0, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// _EmplaceBackwardNeighbor(eit, bhop, parent, child, hits, next_q); +// } +// for (auto eit = +// txn.GetInEdgeIterator(lgraph::EdgeUid(0, vid, edge_lid, 0, 0), true); +// eit.IsValid(); eit.Next()) { +// if (eit.GetLabelId() != edge_lid) break; +// _EmplaceBackwardNeighbor(eit, bhop, parent, child, hits, next_q); +// } +// } +// } +// std::sort(next_q.begin(), next_q.end()); +// backward_q.swap(next_q); +// } +// } +// for (auto &hit : hits) { +// std::vector fpaths; +// std::vector bpaths; +// auto fvid = std::get<0>(hit); +// auto bvid = std::get<1>(hit); +// cypher::Path path; +// path.SetStart(fvid); +// _EnumeratePartialPaths(txn, parent, fvid, parent[fvid], edge_label, path, fpaths); +// path.Clear(); +// path.SetStart(bvid); +// _EnumeratePartialPaths(txn, child, bvid, child[bvid], edge_label, path, bpaths); +// for (auto &fpath : fpaths) { +// fpath.Reverse(); +// fpath.Append(std::get<4>(hit) +// ? lgraph::EdgeUid(fvid, bvid, std::get<2>(hit), 0, std::get<3>(hit)) +// : lgraph::EdgeUid(bvid, fvid, std::get<2>(hit), 0, std::get<3>(hit))); +// for (auto &bpath : bpaths) { +// paths.emplace_back(fpath); +// for (int i = 0; i < (int)bpath.Length(); i++) +// paths.back().Append(bpath.GetNthEdge(i)); +// } +// } +// } +// } + +void AlgoFuncV2::ShortestPath(RTContext *ctx, const Record *record, const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + // CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + // CYPHER_ARG_CHECK(args.size() / 2 == 1, "wrong arguments number") + // CYPHER_ARG_CHECK(args[0].IsString() && + // args[1].IsString() && + // (args.size() == 2 || args[2].type == parser::Expression::MAP), + // "wrong type") + // std::string edge_label; + // EDGE_FILTER_T edge_filter; + // parser::LinkDirection direction = parser::LinkDirection::DIR_NOT_SPECIFIED; + // size_t max_hops = 20; + // if (args.size() == 3) { + // auto &map = args[2].Map(); + // auto it = map.find("relationshipQuery"); + // if (it != map.end()) { + // if (it->second.type != parser::Expression::STRING) CYPHER_TODO(); + // edge_label = it->second.constant.scalar.AsString(); + // } + // auto max = map.find("maxHops"); + // if (max != map.end()) { + // if (max->second.type != parser::Expression::INT) CYPHER_TODO(); + // max_hops = max->second.constant.scalar.integer(); + // } + // auto map_edge_filter = map.find("edgeFilter"); + // if (map_edge_filter != map.end()) { + // if (map_edge_filter->second.type != parser::Expression::MAP) CYPHER_TODO(); + // for (auto &kv : map_edge_filter->second.Map()) { + // if (kv.second.type != parser::Expression::MAP) CYPHER_TODO(); + // std::unordered_map filter_t; + // for (auto filter_pair : kv.second.Map()) { + // lgraph::FieldData field; + // if (!filter_pair.second.IsLiteral()) CYPHER_TODO(); + // field = parser::MakeFieldData(filter_pair.second); + // filter_t.emplace(filter_pair.first, field); + // } + // edge_filter.emplace(kv.first, filter_t); + // } + // } + // auto it_dir = map.find("direction"); + // if (it_dir != map.end()) { + // if (it_dir->second.type != parser::Expression::STRING) CYPHER_TODO(); + // if (it_dir->second.constant.scalar.AsString() == "PointingLeft") { + // direction = parser::LinkDirection::RIGHT_TO_LEFT; + // } else if (it_dir->second.constant.scalar.AsString() == "PointingRight") { + // direction = parser::LinkDirection::LEFT_TO_RIGHT; + // } else if (it_dir->second.constant.scalar.AsString() == "AnyDirection") { + // direction = parser::LinkDirection::DIR_NOT_SPECIFIED; + // } else { + // CYPHER_TODO(); + // } + // } + // } + // CYPHER_THROW_ASSERT(record); + // auto it1 = record->symbol_table->symbols.find(args[0].constant.scalar.AsString()); + // auto it2 = record->symbol_table->symbols.find(args[1].constant.scalar.AsString()); + // if (it1 == record->symbol_table->symbols.end() + // || it2 == record->symbol_table->symbols.end()) { + // CYPHER_TODO(); + // } + // auto start_vid = record->values[it1->second.id].node->PullVid(); + // auto end_vid = record->values[it2->second.id].node->PullVid(); + // cypher::Path path; + // auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + // _P2PUnweightedShortestPath(*ctx->txn_->GetTxn(), start_vid, end_vid, edge_label, max_hops, + // path, edge_filter, direction, std::nullopt); + + // auto pp = global_ptable.GetProcedure("algo.shortestPath"); + // CYPHER_THROW_ASSERT(pp && pp->ContainsYieldItem("nodeCount") && + // pp->ContainsYieldItem("totalCost") && pp->ContainsYieldItem("path")); + // cypher::VEC_STR_V2 titles = ProcedureTitlesV2("algo.shortestPath", yield_items); + // std::unordered_map> lmap = { + // {"nodeCount", + // [&](Record &r) { + // r.AddConstant(lgraph::FieldData( + // static_cast(path.Length() == 0 ? 0 : path.Length() + 1))); + // }}, + // {"totalCost", + // [&](Record &r) { r.AddConstant( + // lgraph::FieldData(static_cast(path.Length()))); }}, + // {"path", [&](Record &r) { r.AddConstant(lgraph::FieldData(path.ToString())); }}}; + // Record r; + // for (auto &title : titles) { + // lmap.find(title)->second(r); + // } + // records->emplace_back(r.Snapshot()); +} + +void AlgoFuncV2::AllShortestPaths(RTContext *ctx, const Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + std::vector *records) { + // CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + // CYPHER_ARG_CHECK(args.size() / 2 == 1, "wrong arguments number") + // CYPHER_ARG_CHECK(args[0].IsString() && + // args[1].IsString() && + // (args.size() == 2 || args[2].type == parser::Expression::MAP), + // "wrong type") + // std::string edge_label; + // if (args.size() == 3) { + // auto &map = args[2].Map(); + // auto it = map.find("relationshipQuery"); + // if (it != map.end()) { + // if (it->second.type != parser::Expression::STRING) CYPHER_TODO(); + // edge_label = it->second.constant.scalar.AsString(); + // } + // } + // CYPHER_THROW_ASSERT(record); + // auto it1 = record->symbol_table->symbols.find(args[0].constant.scalar.AsString()); + // auto it2 = record->symbol_table->symbols.find(args[1].constant.scalar.AsString()); + // if (it1 == record->symbol_table->symbols.end() || + // it2 == record->symbol_table->symbols.end()) { + // CYPHER_TODO(); + // } + // auto start_vid = record->values[it1->second.id].node->PullVid(); + // auto end_vid = record->values[it2->second.id].node->PullVid(); + // std::vector paths; + // auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + // _P2PUnweightedAllShortestPaths(*ctx->txn_->GetTxn(), start_vid, end_vid, edge_label, paths); + + // auto pp = global_ptable.GetProcedure("algo.allShortestPaths"); + // CYPHER_THROW_ASSERT(pp && pp->ContainsYieldItem("nodeIds") && + // pp->ContainsYieldItem("relationshipIds") && pp->ContainsYieldItem("cost")); + // cypher::VEC_STR_V2 titles = ProcedureTitlesV2("algo.allShortestPaths", yield_items); + // std::unordered_map> lmap = { + // {"nodeIds", + // [&](const cypher::Path &path, Record &r) { + // auto ids = cypher::FieldData::Array(0); + // for (int i = 0; i <= (int)path.Length(); i++) { + // ids.array->emplace_back( + // lgraph::FieldData(static_cast(path.ids_[i * 2]))); + // } + // r.AddConstant(ids); + // }}, + // {"relationshipIds", + // [&](const cypher::Path &path, Record &r) { + // auto ids = cypher::FieldData::Array(0); + // for (int i = 0; i < (int)path.Length(); i++) { + // ids.array->emplace_back( + // lgraph::FieldData(_detail::EdgeUid2String(path.GetNthEdge(i)))); + // } + // r.AddConstant(ids); + // }}, + // {"cost", + // [&](const cypher::Path &path, Record &r) { + // r.AddConstant(lgraph::FieldData(static_cast(path.Length()))); + // }}, + // }; + // for (auto &path : paths) { + // Record r; + // for (auto &title : titles) { + // lmap.find(title)->second(path, r); + // } + // records->emplace_back(r.Snapshot()); + // } +} + +void AlgoFuncV2::NativeExtract(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, + const cypher::VEC_STR_V2 &yield_items, + struct std::vector *records) { + // CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + // CYPHER_ARG_CHECK(args.size() / 2 == 1, "wrong arguments number") + // CYPHER_ARG_CHECK( + // args[0].IsString() && args[1].type == parser::Expression::MAP, + // "wrong type") + // auto &config = args[1].Map(); + // auto it1 = config.find("isNode"); + // auto it2 = config.find("field"); + // if (it1 == config.end() || it1->second.type != parser::Expression::BOOL || + // it2 == config.end() || it2->second.type != parser::Expression::STRING) { + // CYPHER_TODO(); + // } + // cypher::FieldData value; + // if (it1->second.constant.scalar.AsBool()) { + // CYPHER_THROW_ASSERT(record); + // auto i = record->symbol_table->symbols.find(args[0].constant.scalar.AsString()); + // if (i == record->symbol_table->symbols.end()) CYPHER_TODO(); + // auto &vid = record->values[i->second.id]; + // auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + // if (vid.IsArray()) { + // value = cypher::FieldData::Array(0); + // for (auto &id : *vid.constant.array) { + // value.array->emplace_back( + // ctx->txn_->GetTxn()->GetVertexField(id.AsInt64(), + // it2->second.constant.scalar.AsString())); + // } + // } else { + // CYPHER_TODO(); + // } + // } else { + // CYPHER_THROW_ASSERT(record); + // auto i = record->symbol_table->symbols.find(args[0].constant.scalar.AsString()); + // if (i == record->symbol_table->symbols.end()) CYPHER_TODO(); + // auto &eid = record->values[i->second.id]; + // if (!eid.IsString()) CYPHER_TODO(); + // auto ac_db = ctx->galaxy_->OpenGraph(ctx->user_, ctx->graph_); + // value = ctx->txn_->GetTxn()->GetEdgeField( + // _detail::ExtractEdgeUid(eid.constant.scalar.AsString()), + // it2->second.constant.scalar.AsString()); + // } + + // auto pp = global_ptable.GetProcedure("algo.native.extract"); + // CYPHER_THROW_ASSERT(pp && pp->ContainsYieldItem("value")); + // cypher::VEC_STR_V2 titles; + // if (yield_items.empty()) { + // for (auto &res : pp->signature.result_list) titles.emplace_back(res.name); + // } else { + // for (auto &item : yield_items) { + // if (!pp->ContainsYieldItem(item)) { + // throw lgraph::CypherException("Unknown procedure output: " + item); + // } + // titles.emplace_back(item); + // } + // } + // std::unordered_map> lmap = { + // {"value", [&](const cypher::FieldData &d, Record &r) { r.AddConstant(d); }}, + // }; + // Record r; + // for (auto &title : titles) { + // lmap.find(title)->second(value, r); + // } + // records->emplace_back(r.Snapshot()); +} + +void AlgoFuncV2::PageRank(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, const cypher::VEC_STR_V2 &yield_items, + struct std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + CYPHER_ARG_CHECK(args.size() == 1, "args number should be 1"); + CYPHER_ARG_CHECK(args[0].IsInteger(), "arg is not int"); + + std::map> node_prs_curr; + std::map> node_prs_next; + auto num_iterations = args[0].constant.scalar.integer(); + auto vertex_num = 0; + double d = (double)0.85; + for (auto v_it = ctx->txn_->GetVertexIterator(); v_it.IsValid(); v_it.Next()) { + if (v_it.GetNumOutEdges() == 0) { + node_prs_curr[v_it.GetId()] = std::make_pair(double(1), v_it.GetNumOutEdges()); + + } else { + node_prs_curr[v_it.GetId()] = + std::make_pair(double(1 / v_it.GetNumOutEdges()), v_it.GetNumOutEdges()); + } + vertex_num++; + } + if (vertex_num == 0) { + return; + } + + while (num_iterations > 0) { + for (auto v_it = ctx->txn_->GetVertexIterator(); v_it.IsValid(); v_it.Next()) { + auto vid = v_it.GetId(); + double sum = 0; + for (auto edge_it = v_it.GetInEdgeIterator(); edge_it.IsValid(); edge_it.Next()) { + if (node_prs_curr[edge_it.GetSrc()].second == 0) { + sum += node_prs_curr[edge_it.GetSrc()].first; + } else { + sum += node_prs_curr[edge_it.GetSrc()].first / + node_prs_curr[edge_it.GetSrc()].second; + } + } + node_prs_next[vid].first = (1 - d) / vertex_num + d * sum; + node_prs_next[vid].second = node_prs_curr[vid].second; + } + node_prs_curr = node_prs_next; + num_iterations--; + } + cypher::VEC_STR_V2 titles = ProcedureTitlesV2("algo.pagerank", yield_items); + std::unordered_map title_exsited; + std::transform(titles.begin(), titles.end(), std::inserter(title_exsited, title_exsited.end()), + [](const std::string &title) { return std::make_pair(title, true); }); + for (auto &node_pr : node_prs_curr) { + cypher::Record r; + cypher::Node n; + if (title_exsited.find("node") != title_exsited.end()) { + n.SetVid(node_pr.first); + r.AddNode(&n); + } + if (title_exsited.find("pr") != title_exsited.end()) { + r.AddConstant(lgraph::FieldData(node_pr.second.first)); + } + records->emplace_back(r.Snapshot()); + } +} + +void AlgoFuncV2::Jaccard(RTContext *ctx, const cypher::Record *record, + const cypher::VEC_EXPR_V2 &args, const cypher::VEC_STR_V2 &yield_items, + struct std::vector *records) { + CYPHER_DB_PROCEDURE_GRAPH_CHECK(); + CYPHER_ARG_CHECK(args.size() == 2, "args number should be 2"); + auto lef_entry = args[0]; + auto rig_entry = args[1]; + CYPHER_ARG_CHECK(lef_entry.IsArray(), "args[0] is not list"); + CYPHER_ARG_CHECK(rig_entry.IsArray(), "args[1] is not list"); + std::unordered_set union_set, intersection; + for (auto &item : *lef_entry.constant.array) { + CYPHER_ARG_CHECK(item.IsInteger(), "item is not integer"); + union_set.emplace(item.AsInt64()); + } + for (auto &item : *rig_entry.constant.array) { + CYPHER_ARG_CHECK(item.IsInteger(), "item is not integer"); + if (union_set.find(item.AsInt64()) != union_set.end()) { + intersection.emplace(item.AsInt64()); + } + } + for (auto &item : *rig_entry.constant.array) { + CYPHER_ARG_CHECK(item.IsInteger(), "item is not integer"); + union_set.emplace(item.AsInt64()); + } + std::unordered_set title_exsited; + cypher::VEC_STR_V2 titles = ProcedureTitlesV2("algo.jaccard", yield_items); + std::transform(titles.begin(), titles.end(), std::inserter(title_exsited, title_exsited.end()), + [](const std::string &title) { return title; }); + if (title_exsited.find("similarity") != title_exsited.end()) { + auto f = union_set.empty() + ? lgraph::FieldData() + : lgraph::FieldData(float(intersection.size()) / union_set.size()); + cypher::Record r; + r.AddConstant(f); + records->emplace_back(r.Snapshot()); + } +} +} // namespace cypher diff --git a/src/cypher/procedure/procedure_v2.h b/src/cypher/procedure/procedure_v2.h new file mode 100644 index 0000000000..b1de662ce7 --- /dev/null +++ b/src/cypher/procedure/procedure_v2.h @@ -0,0 +1,1042 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#pragma once + +#include +#include + +#include "arithmetic/arithmetic_expression.h" +#include "parser/data_typedef.h" +#include "execution_plan/runtime_context.h" +#include "graph/graph.h" +#include "lgraph/lgraph_types.h" + +namespace cypher { + +/* argument and return value type */ +static const std::map ResultTypeNamesV2 = { + {lgraph_api::LGraphType::NUL, "NUL"}, + {lgraph_api::LGraphType::INTEGER, "INTEGER"}, + {lgraph_api::LGraphType::FLOAT, "FLOAT"}, + {lgraph_api::LGraphType::DOUBLE, "DOUBLE"}, + {lgraph_api::LGraphType::BOOLEAN, "BOOLEAN"}, + {lgraph_api::LGraphType::STRING, "STRING"}, + {lgraph_api::LGraphType::NODE, "NODE"}, + {lgraph_api::LGraphType::RELATIONSHIP, "RELATIONSHIP"}, + {lgraph_api::LGraphType::PATH, "PATH"}, + {lgraph_api::LGraphType::LIST, "LIST"}, + {lgraph_api::LGraphType::MAP, "MAP"}, + {lgraph_api::LGraphType::ANY, "ANY"}}; + +static const std::unordered_map ValidAccessLevelsV2 = { + {"NONE", lgraph::AccessLevel::NONE}, + {"READ", lgraph::AccessLevel::READ}, + {"WRITE", lgraph::AccessLevel::WRITE}, + {"FULL", lgraph::AccessLevel::FULL}}; + +static const std::unordered_map ValidFieldAccessLevelsV2 = { + {"NONE", lgraph::FieldAccessLevel::NONE}, + {"READ", lgraph::FieldAccessLevel::READ}, + {"WRITE", lgraph::FieldAccessLevel::WRITE}}; + +static const std::unordered_map ValidPluginTypeV2 = + {{"CPP", lgraph::PluginManager::PluginType::CPP}, + {"PY", lgraph::PluginManager::PluginType::PYTHON}}; + +static const std::unordered_map ValidPluginCodeTypeV2 = { + {"PY", lgraph::plugin::CodeType::PY}, + {"SO", lgraph::plugin::CodeType::SO}, + {"CPP", lgraph::plugin::CodeType::CPP}, + {"ZIP", lgraph::plugin::CodeType::ZIP}}; + +static const int SPEC_MEMBER_SIZE_V2 = 3; + +typedef std::vector VEC_EXPR_V2; +typedef std::vector VEC_STR_V2; +// TODO(anyone) procedure context +typedef std::function *records)> + SA_FUNC_V2; + +class BuiltinProcedureV2 { + static const std::unordered_map type_map_; + + static void _ExtractFds(const VEC_EXPR_V2 &args, std::string &label, std::string &extra, + std::vector &fds); + + static void _ExtractAccessLevel(const VEC_EXPR_V2 &args, std::string &label, + std::unordered_map &leves); + + public: + static void DbSubgraph(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbVertexLabels(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbEdgeLabels(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbIndexes(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbPropertyKeys(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbWarmUp(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbCreateVertexLabel(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbGetLabelSchema(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbGetVertexSchema(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbGetEdgeSchema(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbCreateLabel(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbDeleteLabel(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbAlterLabelDelFields(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbAlterLabelAddFields(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbAlterLabelModFields(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbCreateEdgeLabel(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbAddVertexIndex(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbAddEdgeIndex(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbAddFullTextIndex(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbDeleteFullTextIndex(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbRebuildFullTextIndex(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbFullTextIndexes(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbAddEdgeConstraints(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbClearEdgeConstraints(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsProcedures(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsMetaCountDetail(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsMetaCount(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbmsMetaRefreshCount(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsSecurityChangePassword(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityChangeUserPassword(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecuritySetUserMemoryLimit(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityCreateUser(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityDeleteUser(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityListUsers(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsSecurityShowCurrentUser(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityHostWhitelistList(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityHostWhitelistDelete(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityHostWhitelistAdd(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsGraphCreateGraph(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsGraphModGraph(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsGraphDeleteGraph(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsGraphListGraphs(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsGraphListUserGraphs(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsGraphGetGraphInfo(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsSystemInfo(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsConfigList(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbmsConfigUpdate(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + // take snapshot + static void DbmsTakeSnapshot(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + // list existing backup logs + static void DbmsListBackupLogFiles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityListRoles(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsSecurityCreateRole(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityDeleteRole(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityGetUserInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityGetUserMemoryUsage(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityGetUserPermissions(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityGetRoleInfo(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityDisableRole(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityModRoleDesc(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityRebuildRoleAccessLevel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityModRoleAccessLevel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityModRoleFieldAccessLevel(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityDisableUser(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecuritySetCurrentDesc(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecuritySetUserDesc(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityDeleteUserRoles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityRebuildUserRoles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbmsSecurityAddUserRoles(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbPluginLoadPlugin(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbPluginDeletePlugin(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbPluginListPlugin(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbPluginListUserPlugins(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbPluginGetPluginInfo(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbPluginCallPlugin(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbImportorDataImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbImportorFullImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbImportorFullFileImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbImportorSchemaImportor(RTContext *ctx, const Record *record, + const VEC_EXPR_V2 &args, const VEC_STR_V2 &yield_items, + std::vector *records); + + static void DbDeleteIndex(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbDeleteEdgeIndex(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbFlushDB(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbDropDB(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbTaskListTasks(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbTaskTerminateTask(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + static void DbListLabelIndexes(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbMonitorServerInfo(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbMonitorTuGraphInfo(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void DbmsHaClusterInfo(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); +}; + +class AlgoFuncV2 { + public: + static void ShortestPath(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void AllShortestPaths(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void NativeExtract(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void PageRank(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); + + static void Jaccard(RTContext *ctx, const Record *record, const VEC_EXPR_V2 &args, + const VEC_STR_V2 &yield_items, std::vector *records); +}; + +struct ProcedureV2 { + /* > */ + typedef std::vector>> SIG_SPEC; + typedef SA_FUNC_V2 FUNC; + std::string proc_name; + lgraph_api::SigSpec signature; + FUNC function; + bool read_only; + bool separate_txn; // do this procedure in separate txn + + ProcedureV2(std::string name, FUNC func, const SIG_SPEC &args, const SIG_SPEC &results, + bool ro = true, bool st = false) + : proc_name(std::move(name)), function(std::move(func)), read_only(ro), separate_txn(st) { + std::vector input_list; + std::transform(args.cbegin(), args.cend(), std::back_inserter(input_list), + [](auto arg) -> lgraph_api::Parameter { + return { + .name = arg.first, + .index = arg.second.first, + .type = arg.second.second, + }; + }); + + std::vector yield_items; + std::transform(results.cbegin(), results.cend(), std::back_inserter(yield_items), + [](auto result) -> lgraph_api::Parameter { + return { + .name = result.first, + .index = result.second.first, + .type = result.second.second, + }; + }); + + signature = { + .input_list = std::move(input_list), + .result_list = std::move(yield_items), + }; + } + + ProcedureV2(std::string name, FUNC func, bool ro = true, bool st = false) + : proc_name(std::move(name)), function(std::move(func)), read_only(ro), separate_txn(st) { + signature = { + .input_list = {}, + .result_list = {}, + }; + } + + bool ContainsYieldItem(const std::string &item) { + for (auto &r : signature.result_list) { + if (r.name == item) { + return true; + } + } + return false; + } + + std::string Signature() const { + std::string s; + std::map args, res; + for (auto &p : signature.input_list) { + std::string str; + str.append(p.name).append("::").append(ResultTypeNamesV2.at(p.type)); + args.emplace(p.index, str); + } + for (auto &r : signature.result_list) { + std::string str; + str.append(r.name).append("::").append(ResultTypeNamesV2.at(r.type)); + res.emplace(r.index, str); + } + s.append(proc_name).append("("); + size_t i = 0; + for (auto &a : args) { + s.append(a.second); + if (++i < signature.input_list.size()) s.append(","); + } + s.append(") :: ("); + i = 0; + for (auto &r : res) { + s.append(r.second); + if (++i < signature.result_list.size()) s.append(","); + } + s.append(")"); + return s; + } +}; + +static std::vector global_procedures_v2 = { + ProcedureV2("db.subgraph", BuiltinProcedureV2::DbSubgraph, + ProcedureV2::SIG_SPEC{{"vids", {0, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"subgraph", {0, lgraph_api::LGraphType::STRING}}}), + + ProcedureV2("db.vertexLabels", BuiltinProcedureV2::DbVertexLabels, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"label", {0, lgraph_api::LGraphType::STRING}}}), + + ProcedureV2("db.edgeLabels", BuiltinProcedureV2::DbEdgeLabels, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"label", {0, lgraph_api::LGraphType::STRING}}}), + + ProcedureV2("db.indexes", BuiltinProcedureV2::DbIndexes, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{ + {"label", {0, lgraph_api::LGraphType::STRING}}, + {"field", {1, lgraph_api::LGraphType::STRING}}, + {"label_type", {2, lgraph_api::LGraphType::STRING}}, + {"unique", {3, lgraph_api::LGraphType::BOOLEAN}}, + {"pair_unique", {4, lgraph_api::LGraphType::BOOLEAN}}, + }), + + ProcedureV2("db.listLabelIndexes", BuiltinProcedureV2::DbListLabelIndexes, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"label_type", {1, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{ + {"label", {0, lgraph_api::LGraphType::STRING}}, + {"field", {1, lgraph_api::LGraphType::STRING}}, + {"unique", {2, lgraph_api::LGraphType::BOOLEAN}}, + {"pair_unique", {3, lgraph_api::LGraphType::BOOLEAN}}, + }), + + ProcedureV2("db.propertyKeys", BuiltinProcedureV2::DbPropertyKeys, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"propertyKey", {0, lgraph_api::LGraphType::STRING}}}), + + ProcedureV2("db.warmup", BuiltinProcedureV2::DbWarmUp, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"time_used", {0, lgraph_api::LGraphType::STRING}}}, true, + true), + + ProcedureV2("db.createVertexLabel", BuiltinProcedureV2::DbCreateVertexLabel, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"field_specs", {1, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.createLabel", BuiltinProcedureV2::DbCreateLabel, + ProcedureV2::SIG_SPEC{{"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}, + {"extra", {2, lgraph_api::LGraphType::STRING}}, + {"field_specs", {3, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{}, false, true), + + ProcedureV2("db.getLabelSchema", BuiltinProcedureV2::DbGetLabelSchema, + ProcedureV2::SIG_SPEC{{"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"name", {0, lgraph_api::LGraphType::STRING}}, + {"type", {1, lgraph_api::LGraphType::STRING}}, + {"optional", {2, lgraph_api::LGraphType::BOOLEAN}}}, + true, false), + + ProcedureV2("db.getVertexSchema", BuiltinProcedureV2::DbGetVertexSchema, + ProcedureV2::SIG_SPEC{{"label", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"schema", {0, lgraph_api::LGraphType::MAP}}}, true, false), + + ProcedureV2("db.getEdgeSchema", BuiltinProcedureV2::DbGetEdgeSchema, + ProcedureV2::SIG_SPEC{{"label", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"schema", {0, lgraph_api::LGraphType::MAP}}}, true, false), + + ProcedureV2("db.deleteLabel", BuiltinProcedureV2::DbDeleteLabel, + ProcedureV2::SIG_SPEC{{"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{ + {"", {0, lgraph_api::LGraphType::NUL}}, + }, + false, true), + + ProcedureV2("db.alterLabelDelFields", BuiltinProcedureV2::DbAlterLabelDelFields, + ProcedureV2::SIG_SPEC{{"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}, + {"del_fields", {2, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{ + {"record_affected", {0, lgraph_api::LGraphType::INTEGER}}, + }, + false, true), + + ProcedureV2("db.alterLabelAddFields", BuiltinProcedureV2::DbAlterLabelAddFields, + ProcedureV2::SIG_SPEC{ + {"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}, + {"add_field_spec_values", {2, lgraph_api::LGraphType::LIST}}, + }, + ProcedureV2::SIG_SPEC{ + {"record_affected", {0, lgraph_api::LGraphType::INTEGER}}, + }, + false, true), + + ProcedureV2("db.alterLabelModFields", BuiltinProcedureV2::DbAlterLabelModFields, + ProcedureV2::SIG_SPEC{{"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}, + {"mod_field_specs", {2, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{ + {"record_affected", {0, lgraph_api::LGraphType::INTEGER}}, + }, + false, true), + + ProcedureV2("db.createEdgeLabel", BuiltinProcedureV2::DbCreateEdgeLabel, + ProcedureV2::SIG_SPEC{{"type_name", {0, lgraph_api::LGraphType::STRING}}, + {"field_specs", {1, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.addIndex", BuiltinProcedureV2::DbAddVertexIndex, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"field_name", {1, lgraph_api::LGraphType::STRING}}, + {"unique", {2, lgraph_api::LGraphType::BOOLEAN}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.addEdgeIndex", BuiltinProcedureV2::DbAddEdgeIndex, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"field_name", {1, lgraph_api::LGraphType::STRING}}, + {"unique", {2, lgraph_api::LGraphType::BOOLEAN}}, + {"pair_unique", {2, lgraph_api::LGraphType::BOOLEAN}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.addFullTextIndex", BuiltinProcedureV2::DbAddFullTextIndex, + ProcedureV2::SIG_SPEC{{"is_vertex", {0, lgraph_api::LGraphType::BOOLEAN}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}, + {"field_name", {2, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.deleteFullTextIndex", BuiltinProcedureV2::DbDeleteFullTextIndex, + ProcedureV2::SIG_SPEC{{"is_vertex", {0, lgraph_api::LGraphType::BOOLEAN}}, + {"label_name", {1, lgraph_api::LGraphType::STRING}}, + {"field_name", {2, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.rebuildFullTextIndex", BuiltinProcedureV2::DbRebuildFullTextIndex, + ProcedureV2::SIG_SPEC{{"vertex_labels", {0, lgraph_api::LGraphType::STRING}}, + {"edge_labels", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.fullTextIndexes", BuiltinProcedureV2::DbFullTextIndexes, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"is_vertex", {0, lgraph_api::LGraphType::BOOLEAN}}, + {"label", {1, lgraph_api::LGraphType::STRING}}, + {"field", {2, lgraph_api::LGraphType::STRING}}}), + + ProcedureV2("db.addEdgeConstraints", BuiltinProcedureV2::DbAddEdgeConstraints, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"constraints", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.clearEdgeConstraints", BuiltinProcedureV2::DbClearEdgeConstraints, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.procedures", BuiltinProcedureV2::DbmsProcedures, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"name", {0, lgraph_api::LGraphType::STRING}}, + {"signature", {1, lgraph_api::LGraphType::STRING}}, + {"read_only", {2, lgraph_api::LGraphType::BOOLEAN}}}, + true, false), + + ProcedureV2("dbms.meta.countDetail", BuiltinProcedureV2::DbmsMetaCountDetail, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"is_vertex", {0, lgraph_api::LGraphType::BOOLEAN}}, + {"label", {1, lgraph_api::LGraphType::STRING}}, + {"count", {2, lgraph_api::LGraphType::INTEGER}}}, + true, false), + ProcedureV2("dbms.meta.count", BuiltinProcedureV2::DbmsMetaCount, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"type", {1, lgraph_api::LGraphType::STRING}}, + {"number", {2, lgraph_api::LGraphType::INTEGER}}}, + true, false), + ProcedureV2("dbms.meta.refreshCount", BuiltinProcedureV2::DbmsMetaRefreshCount, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + ProcedureV2("dbms.security.changePassword", BuiltinProcedureV2::DbmsSecurityChangePassword, + ProcedureV2::SIG_SPEC{ + {"current_password", {0, lgraph_api::LGraphType::STRING}}, + {"new_password", {1, lgraph_api::LGraphType::STRING}}, + }, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.changeUserPassword", + BuiltinProcedureV2::DbmsSecurityChangeUserPassword, + ProcedureV2::SIG_SPEC{ + {"user_name", {0, lgraph_api::LGraphType::STRING}}, + {"new_password", {1, lgraph_api::LGraphType::STRING}}, + }, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.createUser", BuiltinProcedureV2::DbmsSecurityCreateUser, + ProcedureV2::SIG_SPEC{{"user_name", {0, lgraph_api::LGraphType::STRING}}, + {"password", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.deleteUser", BuiltinProcedureV2::DbmsSecurityDeleteUser, + ProcedureV2::SIG_SPEC{{"user_name", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.setUserMemoryLimit", + BuiltinProcedureV2::DbmsSecuritySetUserMemoryLimit, + ProcedureV2::SIG_SPEC{ + {"user_name", {0, lgraph_api::LGraphType::STRING}}, + {"MemoryLimit", {1, lgraph_api::LGraphType::INTEGER}}, + }, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.listUsers", BuiltinProcedureV2::DbmsSecurityListUsers, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{ + {"user_name", {0, lgraph_api::LGraphType::STRING}}, + {"user_info", {1, lgraph_api::LGraphType::MAP}}, + }, + true, true), + + ProcedureV2("dbms.security.showCurrentUser", BuiltinProcedureV2::DbmsSecurityShowCurrentUser, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"current_user", {0, lgraph_api::LGraphType::STRING}}}, true, + true), + + ProcedureV2("dbms.security.listAllowedHosts", BuiltinProcedureV2::DbmsSecurityHostWhitelistList, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"host", {0, lgraph_api::LGraphType::STRING}}}, true, true), + + ProcedureV2("dbms.security.deleteAllowedHosts", + BuiltinProcedureV2::DbmsSecurityHostWhitelistDelete, + ProcedureV2::SIG_SPEC{{"hosts", {0, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"record_affected", {0, lgraph_api::LGraphType::INTEGER}}}, + false, true), + + ProcedureV2("dbms.security.addAllowedHosts", BuiltinProcedureV2::DbmsSecurityHostWhitelistAdd, + ProcedureV2::SIG_SPEC{{"hosts", {0, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"num_added", {0, lgraph_api::LGraphType::INTEGER}}}, false, + true), + + ProcedureV2("dbms.graph.createGraph", BuiltinProcedureV2::DbmsGraphCreateGraph, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}, + {"description", {1, lgraph_api::LGraphType::STRING}}, + {"max_size_GB", {2, lgraph_api::LGraphType::INTEGER}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.graph.deleteGraph", BuiltinProcedureV2::DbmsGraphDeleteGraph, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.graph.modGraph", BuiltinProcedureV2::DbmsGraphModGraph, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}, + {"config", {1, lgraph_api::LGraphType::MAP}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.graph.listGraphs", BuiltinProcedureV2::DbmsGraphListGraphs, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}, + {"configuration", {1, lgraph_api::LGraphType::MAP}}}, + true, true), + + ProcedureV2("dbms.graph.listUserGraphs", BuiltinProcedureV2::DbmsGraphListUserGraphs, + ProcedureV2::SIG_SPEC{{"user_name", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}, + {"configuration", {1, lgraph_api::LGraphType::MAP}}}, + true, true), + + ProcedureV2("dbms.graph.getGraphInfo", BuiltinProcedureV2::DbmsGraphGetGraphInfo, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}, + {"configuration", {1, lgraph_api::LGraphType::MAP}}}, + true, true), + + ProcedureV2("dbms.system.info", BuiltinProcedureV2::DbmsSystemInfo, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"name", {0, lgraph_api::LGraphType::STRING}}, + {"value", {1, lgraph_api::LGraphType::ANY}}}, + true, true), + + ProcedureV2("dbms.config.list", BuiltinProcedureV2::DbmsConfigList, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"name", {0, lgraph_api::LGraphType::STRING}}, + {"value", {1, lgraph_api::LGraphType::ANY}}}, + true, true), + + ProcedureV2("dbms.config.update", BuiltinProcedureV2::DbmsConfigUpdate, + ProcedureV2::SIG_SPEC{{"updates", {0, lgraph_api::LGraphType::MAP}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.takeSnapshot", BuiltinProcedureV2::DbmsTakeSnapshot, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"path", {0, lgraph_api::LGraphType::STRING}}}, false), + + ProcedureV2("dbms.listBackupFiles", BuiltinProcedureV2::DbmsListBackupLogFiles, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"file", {0, lgraph_api::LGraphType::STRING}}}, true), + // algo + ProcedureV2("algo.shortestPath", AlgoFuncV2::ShortestPath, + ProcedureV2::SIG_SPEC{ + {"startNode", {0, lgraph_api::LGraphType::NODE}}, + {"endNode", {1, lgraph_api::LGraphType::NODE}}, + {"config", {2, lgraph_api::LGraphType::MAP}}, + }, + ProcedureV2::SIG_SPEC{ + {"nodeCount", {0, lgraph_api::LGraphType::INTEGER}}, + {"totalCost", {1, lgraph_api::LGraphType::FLOAT}}, + {"path", {2, lgraph_api::LGraphType::STRING}}, + }), + + ProcedureV2("algo.allShortestPaths", AlgoFuncV2::AllShortestPaths, + ProcedureV2::SIG_SPEC{ + {"startNode", {0, lgraph_api::LGraphType::NODE}}, + {"endNode", {1, lgraph_api::LGraphType::NODE}}, + {"config", {2, lgraph_api::LGraphType::MAP}}, + }, + ProcedureV2::SIG_SPEC{ + {"nodeIds", {0, lgraph_api::LGraphType::LIST}}, + {"relationshipIds", {1, lgraph_api::LGraphType::LIST}}, + {"cost", {2, lgraph_api::LGraphType::LIST}}, + }), + + ProcedureV2("algo.native.extract", AlgoFuncV2::NativeExtract, + ProcedureV2::SIG_SPEC{ + {"id", {0, lgraph_api::LGraphType::ANY}}, + {"config", {1, lgraph_api::LGraphType::MAP}}, + }, + ProcedureV2::SIG_SPEC{ + {"value", {0, lgraph_api::LGraphType::ANY}}, + }), + + ProcedureV2("algo.pagerank", AlgoFuncV2::PageRank, + ProcedureV2::SIG_SPEC{ + {"num_iterations", {0, lgraph_api::LGraphType::INTEGER}}, + }, + ProcedureV2::SIG_SPEC{{"node", {0, lgraph_api::LGraphType::NODE}}, + {"pr", {1, lgraph_api::LGraphType::FLOAT}}}), + + ProcedureV2("algo.jaccard", AlgoFuncV2::Jaccard, + ProcedureV2::SIG_SPEC{ + {"lhs", {0, lgraph_api::LGraphType::ANY}}, + {"rhs", {0, lgraph_api::LGraphType::ANY}}, + }, + ProcedureV2::SIG_SPEC{ + {"similarity", {0, lgraph_api::LGraphType::FLOAT}}, + }), + + ProcedureV2("dbms.security.listRoles", BuiltinProcedureV2::DbmsSecurityListRoles, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{ + {"role_name", {0, lgraph_api::LGraphType::STRING}}, + {"role_info", {1, lgraph_api::LGraphType::MAP}}, + }, + true, true), + + ProcedureV2("dbms.security.createRole", BuiltinProcedureV2::DbmsSecurityCreateRole, + ProcedureV2::SIG_SPEC{{"role_name", {0, lgraph_api::LGraphType::STRING}}, + {"desc", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.deleteRole", BuiltinProcedureV2::DbmsSecurityDeleteRole, + ProcedureV2::SIG_SPEC{{"role_name", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.getUserInfo", BuiltinProcedureV2::DbmsSecurityGetUserInfo, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"user_info", {0, lgraph_api::LGraphType::MAP}}}, true, true), + + ProcedureV2( + "dbms.security.getUserMemoryUsage", BuiltinProcedureV2::DbmsSecurityGetUserMemoryUsage, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"memory_usage", {0, lgraph_api::LGraphType::INTEGER}}}, true, true), + + ProcedureV2("dbms.security.getUserPermissions", + BuiltinProcedureV2::DbmsSecurityGetUserPermissions, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"user_info", {0, lgraph_api::LGraphType::MAP}}}, true, true), + + ProcedureV2("dbms.security.getRoleInfo", BuiltinProcedureV2::DbmsSecurityGetRoleInfo, + ProcedureV2::SIG_SPEC{{"role", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"role_info", {0, lgraph_api::LGraphType::MAP}}}, true, true), + + ProcedureV2("dbms.security.disableRole", BuiltinProcedureV2::DbmsSecurityDisableRole, + ProcedureV2::SIG_SPEC{{"role", {0, lgraph_api::LGraphType::STRING}}, + {"disable", {1, lgraph_api::LGraphType::BOOLEAN}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.modRoleDesc", BuiltinProcedureV2::DbmsSecurityModRoleDesc, + ProcedureV2::SIG_SPEC{{"role", {0, lgraph_api::LGraphType::STRING}}, + {"description", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.rebuildRoleAccessLevel", + BuiltinProcedureV2::DbmsSecurityRebuildRoleAccessLevel, + ProcedureV2::SIG_SPEC{{"role", {0, lgraph_api::LGraphType::STRING}}, + {"access_level", {1, lgraph_api::LGraphType::MAP}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.modRoleAccessLevel", + BuiltinProcedureV2::DbmsSecurityModRoleAccessLevel, + ProcedureV2::SIG_SPEC{{"role", {0, lgraph_api::LGraphType::STRING}}, + {"access_level", {1, lgraph_api::LGraphType::MAP}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.modRoleFieldAccessLevel", + BuiltinProcedureV2::DbmsSecurityModRoleFieldAccessLevel, + ProcedureV2::SIG_SPEC{{"role", {0, lgraph_api::LGraphType::STRING}}, + {"graph", {0, lgraph_api::LGraphType::STRING}}, + {"label", {0, lgraph_api::LGraphType::STRING}}, + {"field", {0, lgraph_api::LGraphType::STRING}}, + {"label_type", {0, lgraph_api::LGraphType::STRING}}, + {"field_access_level", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.disableUser", BuiltinProcedureV2::DbmsSecurityDisableUser, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}, + {"disable", {1, lgraph_api::LGraphType::BOOLEAN}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.setCurrentDesc", BuiltinProcedureV2::DbmsSecuritySetCurrentDesc, + ProcedureV2::SIG_SPEC{{"description", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.setUserDesc", BuiltinProcedureV2::DbmsSecuritySetUserDesc, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}, + {"description", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.deleteUserRoles", BuiltinProcedureV2::DbmsSecurityDeleteUserRoles, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}, + {"roles", {1, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.rebuildUserRoles", BuiltinProcedureV2::DbmsSecurityRebuildUserRoles, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}, + {"roles", {1, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.security.addUserRoles", BuiltinProcedureV2::DbmsSecurityAddUserRoles, + ProcedureV2::SIG_SPEC{{"user", {0, lgraph_api::LGraphType::STRING}}, + {"roles", {1, lgraph_api::LGraphType::LIST}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.plugin.loadPlugin", BuiltinProcedureV2::DbPluginLoadPlugin, + ProcedureV2::SIG_SPEC{{"plugin_type", {0, lgraph_api::LGraphType::STRING}}, + {"plugin_name", {1, lgraph_api::LGraphType::STRING}}, + {"plugin_content", {2, lgraph_api::LGraphType::ANY}}, + {"code_type", {3, lgraph_api::LGraphType::STRING}}, + {"plugin_description", {4, lgraph_api::LGraphType::STRING}}, + {"read_only", {5, lgraph_api::LGraphType::BOOLEAN}}, + {"version", {6, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.plugin.deletePlugin", BuiltinProcedureV2::DbPluginDeletePlugin, + ProcedureV2::SIG_SPEC{{"plugin_type", {0, lgraph_api::LGraphType::STRING}}, + {"plugin_name", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.plugin.getPluginInfo", BuiltinProcedureV2::DbPluginGetPluginInfo, + ProcedureV2::SIG_SPEC{{"plugin_type", {0, lgraph_api::LGraphType::STRING}}, + {"plugin_name", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"plugin_description", {0, lgraph_api::LGraphType::MAP}}}, + true, true), + + ProcedureV2("db.plugin.listPlugin", BuiltinProcedureV2::DbPluginListPlugin, + ProcedureV2::SIG_SPEC{{"plugin_type", {0, lgraph_api::LGraphType::STRING}}, + {"plugin_version", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"plugin_description", {0, lgraph_api::LGraphType::MAP}}}, + false, true), + + ProcedureV2("db.plugin.listUserPlugins", BuiltinProcedureV2::DbPluginListUserPlugins, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"graph", {0, lgraph_api::LGraphType::STRING}}, + {"plugins", {1, lgraph_api::LGraphType::MAP}}}, + true, true), + + ProcedureV2("db.plugin.callPlugin", BuiltinProcedureV2::DbPluginCallPlugin, + ProcedureV2::SIG_SPEC{{"plugin_type", {0, lgraph_api::LGraphType::STRING}}, + {"plugin_name", {1, lgraph_api::LGraphType::STRING}}, + {"param", {2, lgraph_api::LGraphType::STRING}}, + {"timeout", {3, lgraph_api::LGraphType::DOUBLE}}, + {"in_process", {4, lgraph_api::LGraphType::BOOLEAN}}}, + ProcedureV2::SIG_SPEC{{"result", {0, lgraph_api::LGraphType::STRING}}}, false, + true), + + ProcedureV2("db.importor.dataImportor", BuiltinProcedureV2::DbImportorDataImportor, + ProcedureV2::SIG_SPEC{{"description", {0, lgraph_api::LGraphType::STRING}}, + {"content", {1, lgraph_api::LGraphType::STRING}}, + {"continue_on_error", {2, lgraph_api::LGraphType::BOOLEAN}}, + {"thread_nums", {3, lgraph_api::LGraphType::INTEGER}}, + {"delimiter", {4, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.importor.fullImportor", BuiltinProcedureV2::DbImportorFullImportor, + ProcedureV2::SIG_SPEC{{"conf", {0, lgraph_api::LGraphType::MAP}}}, + ProcedureV2::SIG_SPEC{{"result", {0, lgraph_api::LGraphType::STRING}}}, false, + true), + + ProcedureV2("db.importor.fullFileImportor", BuiltinProcedureV2::DbImportorFullFileImportor, + ProcedureV2::SIG_SPEC{{"graph_name", {0, lgraph_api::LGraphType::STRING}}, + {"path", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.importor.schemaImportor", BuiltinProcedureV2::DbImportorSchemaImportor, + ProcedureV2::SIG_SPEC{{"description", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.deleteIndex", BuiltinProcedureV2::DbDeleteIndex, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"field_name", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.deleteEdgeIndex", BuiltinProcedureV2::DbDeleteEdgeIndex, + ProcedureV2::SIG_SPEC{{"label_name", {0, lgraph_api::LGraphType::STRING}}, + {"field_name", {1, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.flushDB", BuiltinProcedureV2::DbFlushDB, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("db.dropDB", BuiltinProcedureV2::DbDropDB, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2("dbms.task.listTasks", BuiltinProcedureV2::DbTaskListTasks, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{ + {"tasks_info", {1, lgraph_api::LGraphType::MAP}}, + }, + true, true), + + ProcedureV2("dbms.task.terminateTask", BuiltinProcedureV2::DbTaskTerminateTask, + ProcedureV2::SIG_SPEC{{"task_id", {0, lgraph_api::LGraphType::STRING}}}, + ProcedureV2::SIG_SPEC{{"", {0, lgraph_api::LGraphType::NUL}}}, false, true), + + ProcedureV2( + "db.monitor.tuGraphInfo", BuiltinProcedureV2::DbMonitorTuGraphInfo, ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"request", {0, lgraph_api::LGraphType::STRING}}}, false, true), + + ProcedureV2("db.monitor.serverInfo", BuiltinProcedureV2::DbMonitorServerInfo, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"cpu", {0, lgraph_api::LGraphType::STRING}}, + {"memory", {1, lgraph_api::LGraphType::STRING}}, + {"disk_rate", {2, lgraph_api::LGraphType::STRING}}, + {"disk_storage", {3, lgraph_api::LGraphType::STRING}}}, + false, true), + + ProcedureV2("dbms.ha.clusterInfo", BuiltinProcedureV2::DbmsHaClusterInfo, + ProcedureV2::SIG_SPEC{}, + ProcedureV2::SIG_SPEC{{"cluster_info", {0, lgraph_api::LGraphType::LIST}}, + {"is_master", {1, lgraph_api::LGraphType::BOOLEAN}}}, + true, true)}; + +class ProcedureTableV2 { + std::unordered_map ptable_; + + public: + ProcedureTableV2() { RegisterStandaloneFuncs(); } + + void RegisterStandaloneFuncs() { + for (auto &p : global_procedures_v2) { + ptable_.emplace(p.proc_name, p); + } + } + + ProcedureV2 *GetProcedureV2(const std::string &name) { + auto it = ptable_.find(name); + if (it == ptable_.end()) return nullptr; + return &it->second; + } +}; + +static ProcedureTableV2 global_ptable_v2; +} // namespace cypher diff --git a/src/cypher/utils/ast_node_visitor_impl.h b/src/cypher/utils/ast_node_visitor_impl.h index 49a1fe2139..d684dd09b7 100644 --- a/src/cypher/utils/ast_node_visitor_impl.h +++ b/src/cypher/utils/ast_node_visitor_impl.h @@ -133,6 +133,12 @@ class AstNodeVisitorImpl : public geax::frontend::AstNodeVisitor { return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; } + std::any visit(geax::frontend::BSquare* node) override { + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->left()); + ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->right()); + return geax::frontend::GEAXErrorCode::GEAX_SUCCEED; + } + std::any visit(geax::frontend::BAnd* node) override { ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->left()); ACCEPT_AND_CHECK_WITH_ERROR_MSG(node->right()); diff --git a/src/cypher/utils/geax_expr_util.h b/src/cypher/utils/geax_expr_util.h index d1fbe56e91..0f811d6927 100644 --- a/src/cypher/utils/geax_expr_util.h +++ b/src/cypher/utils/geax_expr_util.h @@ -44,12 +44,16 @@ namespace cypher { class AstExprToString : public geax::frontend::AstExprNodeVisitorImpl { public: std::string dump(geax::frontend::Expr* node) { - return std::any_cast(node->accept(*this)); + std::string str; + checkedAnyCast(node->accept(*this), str); + return str; } private: std::any visit(geax::frontend::GetField* node) override { - return std::any_cast(node->expr()->accept(*this)) + "." + node->fieldName(); + std::string str; + checkedAnyCast(node->expr()->accept(*this), str); + return str + "." + node->fieldName(); } std::any visit(geax::frontend::TupleGet* node) override { NOT_SUPPORT_AND_THROW(); } @@ -69,9 +73,11 @@ class AstExprToString : public geax::frontend::AstExprNodeVisitorImpl { std::any visit(geax::frontend::BDiv* node) override { BINARY_EXPR_TOSTRING("/"); } std::any visit(geax::frontend::BMul* node) override { BINARY_EXPR_TOSTRING("*"); } std::any visit(geax::frontend::BMod* node) override { BINARY_EXPR_TOSTRING("%"); } + std::any visit(geax::frontend::BSquare* node) override { BINARY_EXPR_TOSTRING(" ^ "); } std::any visit(geax::frontend::BAnd* node) override { BINARY_EXPR_TOSTRING(" and "); } std::any visit(geax::frontend::BOr* node) override { BINARY_EXPR_TOSTRING(" or "); } std::any visit(geax::frontend::BXor* node) override { BINARY_EXPR_TOSTRING(" xor "); } + std::any visit(geax::frontend::IsLabeled* node) override { UNARY_EXPR_TOSTRING(" isLabel "); } std::any visit(geax::frontend::BBitAnd* node) override { NOT_SUPPORT_AND_THROW(); } std::any visit(geax::frontend::BBitOr* node) override { NOT_SUPPORT_AND_THROW(); } std::any visit(geax::frontend::BBitXor* node) override { NOT_SUPPORT_AND_THROW(); } @@ -120,6 +126,11 @@ class AstExprToString : public geax::frontend::AstExprNodeVisitorImpl { std::any visit(geax::frontend::VNone* node) override { NOT_SUPPORT_AND_THROW(); } std::any visit(geax::frontend::Ref* node) override { return node->name(); } std::any visit(geax::frontend::Param* node) override { NOT_SUPPORT_AND_THROW(); } + std::any visit(geax::frontend::IsNull* node) override { + std::string str = std::any_cast(node->expr()->accept(*this)); + str += " IS NULL"; + return str; + } std::any reportError() override { return error_msg_; } private: diff --git a/src/cypher/utils/geax_util.h b/src/cypher/utils/geax_util.h index 6add411101..5009b08249 100644 --- a/src/cypher/utils/geax_util.h +++ b/src/cypher/utils/geax_util.h @@ -73,3 +73,11 @@ throw lgraph::CypherException(error_msg_); \ } while (0) #endif + +template +void checkedCast(Base* b, Drive*& d) { + static_assert(std::is_base_of::value, + "type `Base` must be the base of type `Drive`"); + d = dynamic_cast(b); + assert(d); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9a2b3e812e..912cab0678 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,6 +31,7 @@ add_executable(unit_test test_cpp_procedure.cpp test_cppresetsdk_json.cpp test_cypher.cpp + test_cypher_v2.cpp test_cypher_plan.cpp test_data_type.cpp test_db_management_client.cpp diff --git a/test/resource/unit_test/add/cypher/add.result b/test/resource/unit_test/add/cypher/add.result new file mode 100644 index 0000000000..73145ba31b --- /dev/null +++ b/test/resource/unit_test/add/cypher/add.result @@ -0,0 +1,26 @@ +CREATE (passerA:Person {name:'Passerby A', birthyear:1983}) CREATE (passerB:Person {name:'Passerby B', birthyear:1984}) CREATE (passerA)-[:MARRIED]->(passerB), (passerB)-[:MARRIED]->(passerA); +[{"":"created 2 vertices, created 2 edges."}] +MATCH (a:Person {name:'Lindsay Lohan'}), (b:Film {title:'The Parent Trap'}) CREATE (a)-[r:DIRECTED]->(b); +[{"":"created 0 vertices, created 1 edges."}] +MATCH (a:Person {name:'Lindsay Lohan'})-[r]->(b:Film {title:'The Parent Trap'}) RETURN r; +[{"r":{"dst":19,"forward":false,"identity":0,"label":"DIRECTED","label_id":3,"src":8,"temporal_id":0}},{"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Halle/Annie"},"src":8,"temporal_id":0}}] +MATCH (a:Film),(b:City) CREATE (a)-[:BORN_IN]->(b) /* 15 edges */; +[{"":"created 0 vertices, created 15 edges."}] +CREATE (sy:City {name:'Sanya'}) RETURN sy,sy.name; +[{"sy":{"identity":23,"label":"City","properties":{"name":"Sanya"}},"sy.name":"Sanya"}] +MATCH (a:Person {name:'Passerby A'}), (sy:City {name:'Sanya'}) CREATE (a)-[r:BORN_IN]->(sy) RETURN a.name,r,sy.name; +[{"a.name":"Passerby A","r":{"dst":23,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":null,"weight":null},"src":21,"temporal_id":0},"sy.name":"Sanya"}] +MATCH (a:Person {name:'Passerby A'}), (sy:City {name:'Sanya'}) WITH a,sy CREATE (a)-[r:BORN_IN]->(sy); +[{"":"created 0 vertices, created 1 edges."}] +CREATE (passerC:Person {name:'Passerby C'}); +[{"":"created 1 vertices, created 0 edges."}] +MATCH (p:Person {name:'Passerby C'}) RETURN exists(p.birthyear) /* false */; +[{"{EXISTS(p.birthyear)}":false}] +WITH 'Passerby D' AS x, 2020 AS y CREATE (:Person {name:x, birthyear:y}); +[{"":"created 1 vertices, created 0 edges."}] +MATCH (a {name:'Passerby A'}) CREATE (:Person {name:'Passerby E', birthyear:a.birthyear}); +[{"":"created 1 vertices, created 0 edges."}] +MATCH (a {name:'Passerby A'}) CREATE (:Person {name:'Passerby F', birthyear:a.birthyear+24}); +[{"":"created 1 vertices, created 0 edges."}] +MATCH (a {name:'Passerby A'}) CREATE (:Person {name:'Passerby G', birthyear:id(a)}); +[{"":"created 1 vertices, created 0 edges."}] diff --git a/test/resource/unit_test/add/cypher/add.test b/test/resource/unit_test/add/cypher/add.test new file mode 100644 index 0000000000..f2c7f0ca1d --- /dev/null +++ b/test/resource/unit_test/add/cypher/add.test @@ -0,0 +1,13 @@ +CREATE (passerA:Person {name:'Passerby A', birthyear:1983}) CREATE (passerB:Person {name:'Passerby B', birthyear:1984}) CREATE (passerA)-[:MARRIED]->(passerB), (passerB)-[:MARRIED]->(passerA); +#MATCH (a:Person {name:'Lindsay Lohan'}), (b:Film {title:'The Parent Trap'}) CREATE (a)-[r:DIRECTED]->(b); +MATCH (a:Person {name:'Lindsay Lohan'})-[r]->(b:Film {title:'The Parent Trap'}) RETURN r; +#MATCH (a:Film),(b:City) CREATE (a)-[:BORN_IN]->(b) /* 15 edges */; +CREATE (sy:City {name:'Sanya'}) RETURN sy,sy.name; +#MATCH (a:Person {name:'Passerby A'}), (sy:City {name:'Sanya'}) CREATE (a)-[r:BORN_IN]->(sy) RETURN a.name,r,sy.name; +#MATCH (a:Person {name:'Passerby A'}), (sy:City {name:'Sanya'}) WITH a,sy CREATE (a)-[r:BORN_IN]->(sy); +CREATE (passerC:Person {name:'Passerby C'}); +MATCH (p:Person {name:'Passerby C'}) RETURN exists(p.birthyear) /* false */; +WITH 'Passerby D' AS x, 2020 AS y CREATE (:Person {name:x, birthyear:y}); +MATCH (a {name:'Passerby A'}) CREATE (:Person {name:'Passerby E', birthyear:a.birthyear}); +MATCH (a {name:'Passerby A'}) CREATE (:Person {name:'Passerby F', birthyear:a.birthyear+24}); +MATCH (a {name:'Passerby A'}) CREATE (:Person {name:'Passerby G', birthyear:id(a)}); diff --git a/test/resource/unit_test/aggregate/cypher/aggregate.result b/test/resource/unit_test/aggregate/cypher/aggregate.result new file mode 100644 index 0000000000..e404d33485 --- /dev/null +++ b/test/resource/unit_test/aggregate/cypher/aggregate.result @@ -0,0 +1,40 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'age', 'INT16', true, 'eyes', 'STRING', true); +[] +CALL db.createEdgeLabel('KNOWS', '[]'); +[] + CREATE (a:Person {name:'A', age:13}) CREATE (b:Person {name:'B', age:33, eyes:'blue'}) CREATE (c:Person {name:'C', age:44, eyes:'blue'}) CREATE (d:Person {name:'D', eyes:'brown'}) CREATE (e:Person {name:'E'}) CREATE (a)-[:KNOWS]->(b), (a)-[:KNOWS]->(c), (a)-[:KNOWS]->(d), (b)-[:KNOWS]->(e), (c)-[:KNOWS]->(e) ; +[{"":"created 5 vertices, created 5 edges."}] +MATCH (n:Person) RETURN avg(n.age) /* 30.0 */; +[{"avg(n.age)":30.0}] +MATCH (n { name: 'A' })-->(x) RETURN count(x) /* 3 */; +[{"count(x)":3}] +MATCH (n:Person) RETURN count(n.age) /* 3 */; +[{"count(n.age)":5}] +MATCH (n:Person) RETURN max(n.age) /* 44 */; +[{"max(n.age)":44.0}] +MATCH (n:Person) RETURN min(n.age) /* 13 */; +[{"min(n.age)":13.0}] +MATCH (n:Person) RETURN percentileCont(n.age, 0.4) /* 29 */; +[{"percentileCont(n.age,0.400000)":29.0}] +MATCH (n:Person) RETURN percentileDisc(n.age, 0.5) /* 33 */; +[{"percentileDisc(n.age,0.500000)":33.0}] +MATCH (n:Person) RETURN stDev(n.age) /* 15.716234 */; +[{"stDev(n.age)":15.716233645501712}] +MATCH (n:Person) RETURN stDevP(n.age) /* 12.832251 */; +[{"stDevP(n.age)":12.832251036613439}] +MATCH (n:Person) RETURN variance(n.age); +[{"variance(n.age)":247.0}] +MATCH (n:Person) RETURN varianceP(n.age); +[{"varianceP(n.age)":164.66666666666666}] +MATCH (n:Person) RETURN collect(n.age) /* 13,33,44 */; +[{"collect(n.age)":[13,33,44]}] +MATCH (n:Person) RETURN collect([n.name,n.age]) /* [[A, 13], [B, 33], [C, 44], [D, null], [E, null]] */; +[{"collect(expr::prop = {n.name},expr::prop = {n.age})":"[[A,13],[B,33],[C,44],[D,NUL],[E,NUL]]"}] +MATCH (n {name: 'A'})-[]->(x) RETURN label(n), n.age, count(*) /* Person,13,3.000000 */; +[{"count(*)":3,"label(n)":"Person","n.age":13}] +MATCH (n {name: 'A'})-[]->(x) RETURN label(n), n, count(*) /* Person,V[0],3.000000 */; +[{"count(*)":3,"label(n)":"Person","n":{"identity":0}}] +MATCH (n {name: 'A'})-[r]->() RETURN type(r), count(*) /* KNOWS,3.00000 */; +[{"count(*)":3,"type(r)":"KNOWS"}] +MATCH (n:Person) WHERE n.age = 13 OR n.age > 40 RETURN count(n) AS nCount; +[{"nCount":2}] diff --git a/test/resource/unit_test/aggregate/cypher/aggregate.test b/test/resource/unit_test/aggregate/cypher/aggregate.test new file mode 100644 index 0000000000..8f54887d64 --- /dev/null +++ b/test/resource/unit_test/aggregate/cypher/aggregate.test @@ -0,0 +1,20 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'age', 'INT16', true, 'eyes', 'STRING', true); +CALL db.createEdgeLabel('KNOWS', '[]'); + CREATE (a:Person {name:'A', age:13}) CREATE (b:Person {name:'B', age:33, eyes:'blue'}) CREATE (c:Person {name:'C', age:44, eyes:'blue'}) CREATE (d:Person {name:'D', eyes:'brown'}) CREATE (e:Person {name:'E'}) CREATE (a)-[:KNOWS]->(b), (a)-[:KNOWS]->(c), (a)-[:KNOWS]->(d), (b)-[:KNOWS]->(e), (c)-[:KNOWS]->(e) ; +MATCH (n:Person) RETURN avg(n.age) /* 30.0 */; +MATCH (n { name: 'A' })-->(x) RETURN count(x) /* 3 */; +MATCH (n:Person) RETURN count(n.age) /* 3 */; +MATCH (n:Person) RETURN max(n.age) /* 44 */; +MATCH (n:Person) RETURN min(n.age) /* 13 */; +MATCH (n:Person) RETURN percentileCont(n.age, 0.4) /* 29 */; +MATCH (n:Person) RETURN percentileDisc(n.age, 0.5) /* 33 */; +MATCH (n:Person) RETURN stDev(n.age) /* 15.716234 */; +MATCH (n:Person) RETURN stDevP(n.age) /* 12.832251 */; +MATCH (n:Person) RETURN variance(n.age); +MATCH (n:Person) RETURN varianceP(n.age); +MATCH (n:Person) RETURN collect(n.age) /* 13,33,44 */; +MATCH (n:Person) RETURN collect([n.name,n.age]) /* [[A, 13], [B, 33], [C, 44], [D, null], [E, null]] */; +MATCH (n {name: 'A'})-[]->(x) RETURN label(n), n.age, count(*) /* Person,13,3.000000 */; +MATCH (n {name: 'A'})-[]->(x) RETURN label(n), n, count(*) /* Person,V[0],3.000000 */; +MATCH (n {name: 'A'})-[r]->() RETURN type(r), count(*) /* KNOWS,3.00000 */; +MATCH (n:Person) WHERE n.age = 13 OR n.age > 40 RETURN count(n) AS nCount; \ No newline at end of file diff --git a/test/resource/unit_test/algo/cypher/algo.result b/test/resource/unit_test/algo/cypher/algo.result new file mode 100644 index 0000000000..e6f755d2e7 --- /dev/null +++ b/test/resource/unit_test/algo/cypher/algo.result @@ -0,0 +1,18 @@ +CALL db.createVertexLabel('Loc', 'name', 'name', 'STRING', false); +[] +CALL db.createEdgeLabel('ROAD', '[]', 'cost', 'FLOAT', false); +[] + CREATE (a:Loc {name:'A'}) CREATE (b:Loc {name:'B'}) CREATE (c:Loc {name:'C'}) CREATE (d:Loc {name:'D'}) CREATE (e:Loc {name:'E'}) CREATE (f:Loc {name:'F'}) CREATE (g:Loc {name:'G'}) CREATE (a)-[:ROAD {cost:50}]->(b) CREATE (a)-[:ROAD {cost:50}]->(c) CREATE (a)-[:ROAD {cost:100}]->(d) CREATE (b)-[:ROAD {cost:40}]->(d) CREATE (c)-[:ROAD {cost:40}]->(d) CREATE (c)-[:ROAD {cost:80}]->(e) CREATE (d)-[:ROAD {cost:30}]->(e) CREATE (d)-[:ROAD {cost:80}]->(f) CREATE (e)-[:ROAD {cost:40}]->(f); +[{"":"created 7 vertices, created 9 edges."}] +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'F'}) CALL algo.shortestPath(n1, n2) YIELD nodeCount RETURN nodeCount; +[{"nodeCount":3}] +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'G'}) CALL algo.shortestPath(n1, n2) YIELD nodeCount RETURN nodeCount; +[{"nodeCount":0}] +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2) YIELD nodeIds,relationshipIds,cost RETURN nodeIds,relationshipIds,cost; +[{"cost":2.0,"nodeIds":[0,2,4],"relationshipIds":"[0_2_0_0_0,2_4_0_0_0]"},{"cost":2.0,"nodeIds":[0,3,4],"relationshipIds":"[0_3_0_0_0,3_4_0_0_0]"}] +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2) YIELD nodeIds,relationshipIds,cost WITH nodeIds,relationshipIds,cost UNWIND relationshipIds AS rid CALL algo.native.extract(rid, {isNode:false, field:'cost'}) YIELD value RETURN value; +[{"value":50.0},{"value":80.0},{"value":100.0},{"value":30.0}] +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2, {relationshipQuery:'ROAD'}) YIELD nodeIds,relationshipIds WITH nodeIds,relationshipIds UNWIND relationshipIds AS rid CALL algo.native.extract(rid, {isNode:false, field:'cost'}) YIELD value RETURN nodeIds, sum(value) AS score; +[{"nodeIds":[0,3,4],"score":130.0},{"nodeIds":[0,2,4],"score":130.0}] +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2, {relationshipQuery:'ROAD'}) YIELD nodeIds,relationshipIds,cost WITH nodeIds,relationshipIds,cost UNWIND relationshipIds AS rid CALL algo.native.extract(rid, {isNode:false, field:'cost'}) YIELD value WITH nodeIds, sum(value) AS score CALL algo.native.extract(nodeIds, {isNode:true, field:'name'}) YIELD value RETURN value, score; +[{"score":130.0,"value":"[A,D,E]"},{"score":130.0,"value":"[A,C,E]"}] diff --git a/test/resource/unit_test/algo/cypher/algo.test b/test/resource/unit_test/algo/cypher/algo.test new file mode 100644 index 0000000000..88c81bfd4d --- /dev/null +++ b/test/resource/unit_test/algo/cypher/algo.test @@ -0,0 +1,9 @@ +CALL db.createVertexLabel('Loc', 'name', 'name', 'STRING', false); +CALL db.createEdgeLabel('ROAD', '[]', 'cost', 'FLOAT', false); + CREATE (a:Loc {name:'A'}) CREATE (b:Loc {name:'B'}) CREATE (c:Loc {name:'C'}) CREATE (d:Loc {name:'D'}) CREATE (e:Loc {name:'E'}) CREATE (f:Loc {name:'F'}) CREATE (g:Loc {name:'G'}) CREATE (a)-[:ROAD {cost:50}]->(b) CREATE (a)-[:ROAD {cost:50}]->(c) CREATE (a)-[:ROAD {cost:100}]->(d) CREATE (b)-[:ROAD {cost:40}]->(d) CREATE (c)-[:ROAD {cost:40}]->(d) CREATE (c)-[:ROAD {cost:80}]->(e) CREATE (d)-[:ROAD {cost:30}]->(e) CREATE (d)-[:ROAD {cost:80}]->(f) CREATE (e)-[:ROAD {cost:40}]->(f); +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'F'}) CALL algo.shortestPath(n1, n2) YIELD nodeCount RETURN nodeCount; +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'G'}) CALL algo.shortestPath(n1, n2) YIELD nodeCount RETURN nodeCount; +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2) YIELD nodeIds,relationshipIds,cost RETURN nodeIds,relationshipIds,cost; +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2) YIELD nodeIds,relationshipIds,cost WITH nodeIds,relationshipIds,cost UNWIND relationshipIds AS rid CALL algo.native.extract(rid, {isNode:false, field:'cost'}) YIELD value RETURN value; +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2, {relationshipQuery:'ROAD'}) YIELD nodeIds,relationshipIds WITH nodeIds,relationshipIds UNWIND relationshipIds AS rid CALL algo.native.extract(rid, {isNode:false, field:'cost'}) YIELD value RETURN nodeIds, sum(value) AS score; +MATCH (n1:Loc {name:'A'}), (n2:Loc {name:'E'}) CALL algo.allShortestPaths(n1, n2, {relationshipQuery:'ROAD'}) YIELD nodeIds,relationshipIds,cost WITH nodeIds,relationshipIds,cost UNWIND relationshipIds AS rid CALL algo.native.extract(rid, {isNode:false, field:'cost'}) YIELD value WITH nodeIds, sum(value) AS score CALL algo.native.extract(nodeIds, {isNode:true, field:'name'}) YIELD value RETURN value, score; \ No newline at end of file diff --git a/test/resource/unit_test/create_label/cypher/create_label.result b/test/resource/unit_test/create_label/cypher/create_label.result new file mode 100644 index 0000000000..0ee6531f58 --- /dev/null +++ b/test/resource/unit_test/create_label/cypher/create_label.result @@ -0,0 +1,20 @@ +CALL db.createLabel('vertex','Person', 'name', ['name', 'string', false], ['birthyear', 'int16', true]); +[] +CALL db.createLabel('vertex', 'City','name', ['name', 'string', false]); +[] +CALL db.createLabel('vertex', 'Film', 'title', ['title', 'string', false]); +[] +CALL db.createLabel('edge', 'HAS_CHILD', '[]'); +[] +CALL db.createLabel('edge', 'MARRIED', '[]'); +[] +CALL db.createLabel('edge', 'BORN_IN', '[]'); +[] +CALL db.createLabel('edge', 'DIRECTED', '[]'); +[] +CALL db.createLabel('edge', 'WROTE_MUSIC_FOR', '[]'); +[] +CALL db.createLabel('edge', 'ACTED_IN', '[]', ['charactername', 'string', true]); +[] + CREATE (rachel:Person:Actor {name: 'Rachel Kempson', birthyear: 1910}) CREATE (michael:Person:Actor {name: 'Michael Redgrave', birthyear: 1908}) CREATE (vanessa:Person:Actor {name: 'Vanessa Redgrave', birthyear: 1937}) CREATE (corin:Person:Actor {name: 'Corin Redgrave', birthyear: 1939}) CREATE (liam:Person:Actor {name: 'Liam Neeson', birthyear: 1952}) CREATE (natasha:Person:Actor {name: 'Natasha Richardson', birthyear: 1963}) CREATE (richard:Person:Actor {name: 'Richard Harris', birthyear: 1930}) CREATE (dennis:Person:Actor {name: 'Dennis Quaid', birthyear: 1954}) CREATE (lindsay:Person:Actor {name: 'Lindsay Lohan', birthyear: 1986}) CREATE (jemma:Person:Actor {name: 'Jemma Redgrave', birthyear: 1965}) CREATE (roy:Person:Actor {name: 'Roy Redgrave', birthyear: 1873}) CREATE (john:Person {name: 'John Williams', birthyear: 1932}) CREATE (christopher:Person {name: 'Christopher Nolan', birthyear: 1970}) CREATE (newyork:City {name: 'New York'}) CREATE (london:City {name: 'London'}) CREATE (houston:City {name: 'Houston'}) CREATE (mrchips:Film {title: 'Goodbye, Mr. Chips'}) CREATE (batmanbegins:Film {title: 'Batman Begins'}) CREATE (harrypotter:Film {title: 'Harry Potter and the Sorcerer\'s Stone'}) CREATE (parent:Film {title: 'The Parent Trap'}) CREATE (camelot:Film {title: 'Camelot'}) CREATE (rachel)-[:HAS_CHILD]->(vanessa), (rachel)-[:HAS_CHILD]->(corin), (michael)-[:HAS_CHILD]->(vanessa), (michael)-[:HAS_CHILD]->(corin), (corin)-[:HAS_CHILD]->(jemma), (vanessa)-[:HAS_CHILD]->(natasha), (roy)-[:HAS_CHILD]->(michael), (rachel)-[:MARRIED]->(michael), (michael)-[:MARRIED]->(rachel), (natasha)-[:MARRIED]->(liam), (liam)-[:MARRIED]->(natasha), (vanessa)-[:BORN_IN]->(london),(natasha)-[:BORN_IN]->(london), (christopher)-[:BORN_IN]->(london), (dennis)-[:BORN_IN]->(houston), (lindsay)-[:BORN_IN]->(newyork), (john)-[:BORN_IN]->(newyork), (christopher)-[:DIRECTED]->(batmanbegins), (john)-[:WROTE_MUSIC_FOR]->(harrypotter), (john)-[:WROTE_MUSIC_FOR]->(mrchips), (michael)-[:ACTED_IN {charactername: 'The Headmaster'}]->(mrchips), (vanessa)-[:ACTED_IN {charactername: 'Guenevere'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'King Arthur'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'Albus Dumbledore'}]->(harrypotter), (natasha)-[:ACTED_IN {charactername: 'Liz James'}]->(parent), (dennis)-[:ACTED_IN {charactername: 'Nick Parker'}]->(parent), (lindsay)-[:ACTED_IN {charactername: 'Halle/Annie'}]->(parent), (liam)-[:ACTED_IN {charactername: 'Henri Ducard'}]->(batmanbegins) ; +[{"":"created 21 vertices, created 28 edges."}] diff --git a/test/resource/unit_test/create_label/cypher/create_label.test b/test/resource/unit_test/create_label/cypher/create_label.test new file mode 100644 index 0000000000..011ea57560 --- /dev/null +++ b/test/resource/unit_test/create_label/cypher/create_label.test @@ -0,0 +1,10 @@ +CALL db.createLabel('vertex','Person', 'name', ['name', 'string', false], ['birthyear', 'int16', true]); +CALL db.createLabel('vertex', 'City','name', ['name', 'string', false]); +CALL db.createLabel('vertex', 'Film', 'title', ['title', 'string', false]); +CALL db.createLabel('edge', 'HAS_CHILD', '[]'); +CALL db.createLabel('edge', 'MARRIED', '[]'); +CALL db.createLabel('edge', 'BORN_IN', '[]'); +CALL db.createLabel('edge', 'DIRECTED', '[]'); +CALL db.createLabel('edge', 'WROTE_MUSIC_FOR', '[]'); +CALL db.createLabel('edge', 'ACTED_IN', '[]', ['charactername', 'string', true]); + CREATE (rachel:Person:Actor {name: 'Rachel Kempson', birthyear: 1910}) CREATE (michael:Person:Actor {name: 'Michael Redgrave', birthyear: 1908}) CREATE (vanessa:Person:Actor {name: 'Vanessa Redgrave', birthyear: 1937}) CREATE (corin:Person:Actor {name: 'Corin Redgrave', birthyear: 1939}) CREATE (liam:Person:Actor {name: 'Liam Neeson', birthyear: 1952}) CREATE (natasha:Person:Actor {name: 'Natasha Richardson', birthyear: 1963}) CREATE (richard:Person:Actor {name: 'Richard Harris', birthyear: 1930}) CREATE (dennis:Person:Actor {name: 'Dennis Quaid', birthyear: 1954}) CREATE (lindsay:Person:Actor {name: 'Lindsay Lohan', birthyear: 1986}) CREATE (jemma:Person:Actor {name: 'Jemma Redgrave', birthyear: 1965}) CREATE (roy:Person:Actor {name: 'Roy Redgrave', birthyear: 1873}) CREATE (john:Person {name: 'John Williams', birthyear: 1932}) CREATE (christopher:Person {name: 'Christopher Nolan', birthyear: 1970}) CREATE (newyork:City {name: 'New York'}) CREATE (london:City {name: 'London'}) CREATE (houston:City {name: 'Houston'}) CREATE (mrchips:Film {title: 'Goodbye, Mr. Chips'}) CREATE (batmanbegins:Film {title: 'Batman Begins'}) CREATE (harrypotter:Film {title: 'Harry Potter and the Sorcerer\'s Stone'}) CREATE (parent:Film {title: 'The Parent Trap'}) CREATE (camelot:Film {title: 'Camelot'}) CREATE (rachel)-[:HAS_CHILD]->(vanessa), (rachel)-[:HAS_CHILD]->(corin), (michael)-[:HAS_CHILD]->(vanessa), (michael)-[:HAS_CHILD]->(corin), (corin)-[:HAS_CHILD]->(jemma), (vanessa)-[:HAS_CHILD]->(natasha), (roy)-[:HAS_CHILD]->(michael), (rachel)-[:MARRIED]->(michael), (michael)-[:MARRIED]->(rachel), (natasha)-[:MARRIED]->(liam), (liam)-[:MARRIED]->(natasha), (vanessa)-[:BORN_IN]->(london),(natasha)-[:BORN_IN]->(london), (christopher)-[:BORN_IN]->(london), (dennis)-[:BORN_IN]->(houston), (lindsay)-[:BORN_IN]->(newyork), (john)-[:BORN_IN]->(newyork), (christopher)-[:DIRECTED]->(batmanbegins), (john)-[:WROTE_MUSIC_FOR]->(harrypotter), (john)-[:WROTE_MUSIC_FOR]->(mrchips), (michael)-[:ACTED_IN {charactername: 'The Headmaster'}]->(mrchips), (vanessa)-[:ACTED_IN {charactername: 'Guenevere'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'King Arthur'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'Albus Dumbledore'}]->(harrypotter), (natasha)-[:ACTED_IN {charactername: 'Liz James'}]->(parent), (dennis)-[:ACTED_IN {charactername: 'Nick Parker'}]->(parent), (lindsay)-[:ACTED_IN {charactername: 'Halle/Annie'}]->(parent), (liam)-[:ACTED_IN {charactername: 'Henri Ducard'}]->(batmanbegins) ; \ No newline at end of file diff --git a/test/resource/unit_test/create_yago/cypher/create_yago.result b/test/resource/unit_test/create_yago/cypher/create_yago.result new file mode 100644 index 0000000000..c174abff31 --- /dev/null +++ b/test/resource/unit_test/create_yago/cypher/create_yago.result @@ -0,0 +1,21 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'birthyear', 'INT16', true); +[] +CALL db.createVertexLabel('City', 'name', 'name', 'STRING', false); +[] +CALL db.createVertexLabel('Film', 'title', 'title', 'STRING', false); +[] +CALL db.createEdgeLabel('HAS_CHILD', '[]'); +[] +CALL db.createEdgeLabel('MARRIED', '[]'); +[] +CALL db.createEdgeLabel('BORN_IN', '[]'); +[] +CALL db.createEdgeLabel('DIRECTED', '[]'); +[] +CALL db.createEdgeLabel('WROTE_MUSIC_FOR', '[]'); +[] +CALL db.createEdgeLabel('ACTED_IN', '[]', 'charactername', 'STRING', false); +[] + CREATE (rachel:Person:Actor {name: 'Rachel Kempson', birthyear: 1910}) CREATE (michael:Person:Actor {name: 'Michael Redgrave', birthyear: 1908}) CREATE (vanessa:Person:Actor {name: 'Vanessa Redgrave', birthyear: 1937}) CREATE (corin:Person:Actor {name: 'Corin Redgrave', birthyear: 1939}) CREATE (liam:Person:Actor {name: 'Liam Neeson', birthyear: 1952}) CREATE (natasha:Person:Actor {name: 'Natasha Richardson', birthyear: 1963}) CREATE (richard:Person:Actor {name: 'Richard Harris', birthyear: 1930}) CREATE (dennis:Person:Actor {name: 'Dennis Quaid', birthyear: 1954}) CREATE (lindsay:Person:Actor {name: 'Lindsay Lohan', birthyear: 1986}) CREATE (jemma:Person:Actor {name: 'Jemma Redgrave', birthyear: 1965}) CREATE (roy:Person:Actor {name: 'Roy Redgrave', birthyear: 1873}) CREATE (john:Person {name: 'John Williams', birthyear: 1932}) CREATE (christopher:Person {name: 'Christopher Nolan', birthyear: 1970}) CREATE (newyork:City {name: 'New York'}) CREATE (london:City {name: 'London'}) CREATE (houston:City {name: 'Houston'}) CREATE (mrchips:Film {title: 'Goodbye, Mr. Chips'}) CREATE (batmanbegins:Film {title: 'Batman Begins'}) CREATE (harrypotter:Film {title: 'Harry Potter and the Sorcerer\'s Stone'}) CREATE (parent:Film {title: 'The Parent Trap'}) CREATE (camelot:Film {title: 'Camelot'}) CREATE (rachel)-[:HAS_CHILD]->(vanessa), (rachel)-[:HAS_CHILD]->(corin), (michael)-[:HAS_CHILD]->(vanessa), (michael)-[:HAS_CHILD]->(corin), (corin)-[:HAS_CHILD]->(jemma), (vanessa)-[:HAS_CHILD]->(natasha), (roy)-[:HAS_CHILD]->(michael), (rachel)-[:MARRIED]->(michael), (michael)-[:MARRIED]->(rachel), (natasha)-[:MARRIED]->(liam), (liam)-[:MARRIED]->(natasha), (vanessa)-[:BORN_IN]->(london), (natasha)-[:BORN_IN]->(london), (christopher)-[:BORN_IN]->(london), (dennis)-[:BORN_IN]->(houston), (lindsay)-[:BORN_IN]->(newyork), (john)-[:BORN_IN]->(newyork), (christopher)-[:DIRECTED]->(batmanbegins), (john)-[:WROTE_MUSIC_FOR]->(harrypotter), (john)-[:WROTE_MUSIC_FOR]->(mrchips), (michael)-[:ACTED_IN {charactername: 'The Headmaster'}]->(mrchips), (vanessa)-[:ACTED_IN {charactername: 'Guenevere'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'King Arthur'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'Albus Dumbledore'}]->(harrypotter), (natasha)-[:ACTED_IN {charactername: 'Liz James'}]->(parent), (dennis)-[:ACTED_IN {charactername: 'Nick Parker'}]->(parent),(lindsay)-[:ACTED_IN {charactername: 'Halle/Annie'}]->(parent), (liam)-[:ACTED_IN {charactername: 'Henri Ducard'}]->(batmanbegins) ; +[{"":"created 21 vertices, created 28 edges."}] + diff --git a/test/resource/unit_test/create_yago/cypher/create_yago.test b/test/resource/unit_test/create_yago/cypher/create_yago.test new file mode 100644 index 0000000000..698f2569a1 --- /dev/null +++ b/test/resource/unit_test/create_yago/cypher/create_yago.test @@ -0,0 +1,10 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'birthyear', 'INT16', true); +CALL db.createVertexLabel('City', 'name', 'name', 'STRING', false); +CALL db.createVertexLabel('Film', 'title', 'title', 'STRING', false); +CALL db.createEdgeLabel('HAS_CHILD', '[]'); +CALL db.createEdgeLabel('MARRIED', '[]'); +CALL db.createEdgeLabel('BORN_IN', '[]'); +CALL db.createEdgeLabel('DIRECTED', '[]'); +CALL db.createEdgeLabel('WROTE_MUSIC_FOR', '[]'); +CALL db.createEdgeLabel('ACTED_IN', '[]', 'charactername', 'STRING', false); + CREATE (rachel:Person:Actor {name: 'Rachel Kempson', birthyear: 1910}) CREATE (michael:Person:Actor {name: 'Michael Redgrave', birthyear: 1908}) CREATE (vanessa:Person:Actor {name: 'Vanessa Redgrave', birthyear: 1937}) CREATE (corin:Person:Actor {name: 'Corin Redgrave', birthyear: 1939}) CREATE (liam:Person:Actor {name: 'Liam Neeson', birthyear: 1952}) CREATE (natasha:Person:Actor {name: 'Natasha Richardson', birthyear: 1963}) CREATE (richard:Person:Actor {name: 'Richard Harris', birthyear: 1930}) CREATE (dennis:Person:Actor {name: 'Dennis Quaid', birthyear: 1954}) CREATE (lindsay:Person:Actor {name: 'Lindsay Lohan', birthyear: 1986}) CREATE (jemma:Person:Actor {name: 'Jemma Redgrave', birthyear: 1965}) CREATE (roy:Person:Actor {name: 'Roy Redgrave', birthyear: 1873}) CREATE (john:Person {name: 'John Williams', birthyear: 1932}) CREATE (christopher:Person {name: 'Christopher Nolan', birthyear: 1970}) CREATE (newyork:City {name: 'New York'}) CREATE (london:City {name: 'London'}) CREATE (houston:City {name: 'Houston'}) CREATE (mrchips:Film {title: 'Goodbye, Mr. Chips'}) CREATE (batmanbegins:Film {title: 'Batman Begins'}) CREATE (harrypotter:Film {title: 'Harry Potter and the Sorcerer\'s Stone'}) CREATE (parent:Film {title: 'The Parent Trap'}) CREATE (camelot:Film {title: 'Camelot'}) CREATE (rachel)-[:HAS_CHILD]->(vanessa), (rachel)-[:HAS_CHILD]->(corin), (michael)-[:HAS_CHILD]->(vanessa), (michael)-[:HAS_CHILD]->(corin), (corin)-[:HAS_CHILD]->(jemma), (vanessa)-[:HAS_CHILD]->(natasha), (roy)-[:HAS_CHILD]->(michael), (rachel)-[:MARRIED]->(michael), (michael)-[:MARRIED]->(rachel), (natasha)-[:MARRIED]->(liam), (liam)-[:MARRIED]->(natasha), (vanessa)-[:BORN_IN]->(london), (natasha)-[:BORN_IN]->(london), (christopher)-[:BORN_IN]->(london), (dennis)-[:BORN_IN]->(houston), (lindsay)-[:BORN_IN]->(newyork), (john)-[:BORN_IN]->(newyork), (christopher)-[:DIRECTED]->(batmanbegins), (john)-[:WROTE_MUSIC_FOR]->(harrypotter), (john)-[:WROTE_MUSIC_FOR]->(mrchips), (michael)-[:ACTED_IN {charactername: 'The Headmaster'}]->(mrchips), (vanessa)-[:ACTED_IN {charactername: 'Guenevere'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'King Arthur'}]->(camelot), (richard)-[:ACTED_IN {charactername: 'Albus Dumbledore'}]->(harrypotter), (natasha)-[:ACTED_IN {charactername: 'Liz James'}]->(parent), (dennis)-[:ACTED_IN {charactername: 'Nick Parker'}]->(parent),(lindsay)-[:ACTED_IN {charactername: 'Halle/Annie'}]->(parent), (liam)-[:ACTED_IN {charactername: 'Henri Ducard'}]->(batmanbegins) ; \ No newline at end of file diff --git a/test/resource/unit_test/delete/cypher/delete.result b/test/resource/unit_test/delete/cypher/delete.result new file mode 100644 index 0000000000..456d251578 --- /dev/null +++ b/test/resource/unit_test/delete/cypher/delete.result @@ -0,0 +1,23 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'age', 'INT16', true, 'eyes', 'STRING', true); +[] +CALL db.createEdgeLabel('KNOWS', '[]', 'weight', 'INT16', true); +[] + CREATE (a:Person {name:'A', age:13}) CREATE (b:Person {name:'B', age:33, eyes:'blue'}) CREATE (c:Person {name:'C', age:44, eyes:'blue'}) CREATE (d:Person {name:'D', eyes:'brown'}) CREATE (e:Person {name:'E'}) CREATE (f:Person {name:'F', age:1}) CREATE (g:Person {name:'G', age:2}) CREATE (h:Person {name:'H', age:2}) CREATE (i1:Person {name:'I', age:3}) CREATE (a)-[:KNOWS {weight:10}]->(b), (a)-[:KNOWS {weight:15}]->(c), (a)-[:KNOWS {weight:40}]->(d), (b)-[:KNOWS {weight:20}]->(e),(b)-[:KNOWS {weight:25}]->(f), (c)-[:KNOWS {weight:12}]->(e), (d)-[:KNOWS {weight:4}]->(a), (f)-[:KNOWS {weight:0}]->(g), (f)-[:KNOWS {weight:0}]->(h), (f)-[:KNOWS {weight:0}]->(i1) ; +[{"":"created 9 vertices, created 10 edges."}] +match (n)-[r]->(m) return r,properties(r) /*debug*/; +[{"properties(r)":{"_EID_":"0_1_0_0_0","_LABEL_":"KNOWS","weight":10},"r":{"dst":1,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":10},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"0_2_0_0_0","_LABEL_":"KNOWS","weight":15},"r":{"dst":2,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":15},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"0_3_0_0_0","_LABEL_":"KNOWS","weight":40},"r":{"dst":3,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":40},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"1_4_0_0_0","_LABEL_":"KNOWS","weight":20},"r":{"dst":4,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":20},"src":1,"temporal_id":0}},{"properties(r)":{"_EID_":"1_5_0_0_0","_LABEL_":"KNOWS","weight":25},"r":{"dst":5,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":25},"src":1,"temporal_id":0}},{"properties(r)":{"_EID_":"2_4_0_0_0","_LABEL_":"KNOWS","weight":12},"r":{"dst":4,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":12},"src":2,"temporal_id":0}},{"properties(r)":{"_EID_":"3_0_0_0_0","_LABEL_":"KNOWS","weight":4},"r":{"dst":0,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":4},"src":3,"temporal_id":0}},{"properties(r)":{"_EID_":"5_6_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":6,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}},{"properties(r)":{"_EID_":"5_7_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":7,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}},{"properties(r)":{"_EID_":"5_8_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":8,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}}] +MATCH (n {name:'D'}) DELETE n; +[{"":"deleted 1 vertices, deleted 2 edges."}] +MATCH (n {name:'B'})-[r:KNOWS]->() DELETE r; +[{"":"deleted 0 vertices, deleted 2 edges."}] +MATCH (n:Person {name:'F'})-[r:KNOWS]->(m:Person {name:'I'}) DELETE r; +[{"":"deleted 0 vertices, deleted 1 edges."}] +#MATCH (n:Person {name:'A'}),(m:Person {name:'C'}) WITH n,m MATCH (n)-[r]->(m) DELETE r; +match (n)-[r]->(m) return r,properties(r) /*debug*/; +[{"properties(r)":{"_EID_":"0_1_0_0_0","_LABEL_":"KNOWS","weight":10},"r":{"dst":1,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":10},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"0_2_0_0_0","_LABEL_":"KNOWS","weight":15},"r":{"dst":2,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":15},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"2_4_0_0_0","_LABEL_":"KNOWS","weight":12},"r":{"dst":4,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":12},"src":2,"temporal_id":0}},{"properties(r)":{"_EID_":"5_6_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":6,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}},{"properties(r)":{"_EID_":"5_7_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":7,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}}] +MATCH (n:Person {name:'A'}) DELETE n; +[{"":"deleted 1 vertices, deleted 2 edges."}] +MATCH (n:Person {name:'B'}) WITH n DELETE n; +[{"":"deleted 1 vertices, deleted 0 edges."}] +match (n) return n,properties(n) /*debug*/; +[{"n":{"identity":2,"label":"Person","properties":{"age":44,"eyes":"blue","name":"C"}},"properties(n)":{"_LABEL_":"Person","_VID_":2,"age":44,"eyes":"blue","name":"C"}},{"n":{"identity":4,"label":"Person","properties":{"age":null,"eyes":null,"name":"E"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":4,\"age\":NUL,\"name\":\"E\",\"eyes\":NUL}"},{"n":{"identity":5,"label":"Person","properties":{"age":1,"eyes":null,"name":"F"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":5,\"age\":1,\"name\":\"F\",\"eyes\":NUL}"},{"n":{"identity":6,"label":"Person","properties":{"age":2,"eyes":null,"name":"G"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":6,\"age\":2,\"name\":\"G\",\"eyes\":NUL}"},{"n":{"identity":7,"label":"Person","properties":{"age":2,"eyes":null,"name":"H"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":7,\"age\":2,\"name\":\"H\",\"eyes\":NUL}"},{"n":{"identity":8,"label":"Person","properties":{"age":3,"eyes":null,"name":"I"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":8,\"age\":3,\"name\":\"I\",\"eyes\":NUL}"}] diff --git a/test/resource/unit_test/delete/cypher/delete.test b/test/resource/unit_test/delete/cypher/delete.test new file mode 100644 index 0000000000..9cc177e99c --- /dev/null +++ b/test/resource/unit_test/delete/cypher/delete.test @@ -0,0 +1,12 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'age', 'INT16', true, 'eyes', 'STRING', true); +CALL db.createEdgeLabel('KNOWS', '[]', 'weight', 'INT16', true); + CREATE (a:Person {name:'A', age:13}) CREATE (b:Person {name:'B', age:33, eyes:'blue'}) CREATE (c:Person {name:'C', age:44, eyes:'blue'}) CREATE (d:Person {name:'D', eyes:'brown'}) CREATE (e:Person {name:'E'}) CREATE (f:Person {name:'F', age:1}) CREATE (g:Person {name:'G', age:2}) CREATE (h:Person {name:'H', age:2}) CREATE (i1:Person {name:'I', age:3}) CREATE (a)-[:KNOWS {weight:10}]->(b), (a)-[:KNOWS {weight:15}]->(c), (a)-[:KNOWS {weight:40}]->(d), (b)-[:KNOWS {weight:20}]->(e),(b)-[:KNOWS {weight:25}]->(f), (c)-[:KNOWS {weight:12}]->(e), (d)-[:KNOWS {weight:4}]->(a), (f)-[:KNOWS {weight:0}]->(g), (f)-[:KNOWS {weight:0}]->(h), (f)-[:KNOWS {weight:0}]->(i1) ; +match (n)-[r]->(m) return r,properties(r) /*debug*/; +MATCH (n {name:'D'}) DELETE n; +MATCH (n {name:'B'})-[r:KNOWS]->() DELETE r; +MATCH (n:Person {name:'F'})-[r:KNOWS]->(m:Person {name:'I'}) DELETE r; +#MATCH (n:Person {name:'A'}),(m:Person {name:'C'}) WITH n,m MATCH (n)-[r]->(m) DELETE r; +match (n)-[r]->(m) return r,properties(r) /*debug*/; +MATCH (n:Person {name:'A'}) DELETE n; +MATCH (n:Person {name:'B'}) WITH n DELETE n; +match (n) return n,properties(n) /*debug*/; \ No newline at end of file diff --git a/test/resource/unit_test/edge_id_query/cypher/edge_id_query.result b/test/resource/unit_test/edge_id_query/cypher/edge_id_query.result new file mode 100644 index 0000000000..b3b84aac96 --- /dev/null +++ b/test/resource/unit_test/edge_id_query/cypher/edge_id_query.result @@ -0,0 +1,24 @@ +MATCH ()-[r]->() RETURN euid(r) /* 28 */; +[{"euid(r)":"0_2_0_0_0"},{"euid(r)":"0_3_0_0_0"},{"euid(r)":"0_1_1_0_0"},{"euid(r)":"1_2_0_0_0"},{"euid(r)":"1_3_0_0_0"},{"euid(r)":"1_0_1_0_0"},{"euid(r)":"1_16_5_0_0"},{"euid(r)":"2_5_0_0_0"},{"euid(r)":"2_14_2_0_0"},{"euid(r)":"2_20_5_0_0"},{"euid(r)":"3_9_0_0_0"},{"euid(r)":"4_5_1_0_0"},{"euid(r)":"4_17_5_0_0"},{"euid(r)":"5_4_1_0_0"},{"euid(r)":"5_14_2_0_0"},{"euid(r)":"5_19_5_0_0"},{"euid(r)":"6_18_5_0_0"},{"euid(r)":"6_20_5_0_0"},{"euid(r)":"7_15_2_0_0"},{"euid(r)":"7_19_5_0_0"},{"euid(r)":"8_13_2_0_0"},{"euid(r)":"8_19_5_0_0"},{"euid(r)":"10_1_0_0_0"},{"euid(r)":"11_13_2_0_0"},{"euid(r)":"11_16_4_0_0"},{"euid(r)":"11_18_4_0_0"},{"euid(r)":"12_14_2_0_0"},{"euid(r)":"12_17_3_0_0"}] +MATCH ()-[r]->() RETURN id(r) /* 28 */; +[{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0},{"id(r)":0}] +MATCH (n),(m) WHERE id(n)=0 and id(m)=1 CREATE (n)-[r:ACTED_IN {charactername: "testaha"}]->(m) RETURN r; +[{"r":{"dst":1,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"testaha"},"src":0,"temporal_id":0}}] +MATCH (n),(m),(k) WHERE id(n)=0 and id(m)=2 and id(k)=3 CREATE (n)-[r:ACTED_IN {charactername: "testaha"}]->(m),(n)-[q:MARRIED]->(k) RETURN r,q; +[{"q":{"dst":3,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},"r":{"dst":2,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"testaha"},"src":0,"temporal_id":0}}] +MATCH (n)-[e]->() where id(n)=4 return euid(e); +[{"euid(e)":"4_5_1_0_0"},{"euid(e)":"4_17_5_0_0"}] +MATCH ()-[e]->(n) where id(n)=4 return euid(e); +[{"euid(e)":"5_4_1_0_0"}] +MATCH (n)-[e]-() where id(n)=4 return euid(e); +[{"euid(e)":"4_5_1_0_0"},{"euid(e)":"4_17_5_0_0"},{"euid(e)":"5_4_1_0_0"}] +MATCH ()-[e]->() where euid(e)="0_2_0_0_0" return e,labels(e),properties(e); +[{"e":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},"labels(e)":"[HAS_CHILD]","properties(e)":{"_EID_":"0_2_0_0_0","_LABEL_":"HAS_CHILD"}}] +MATCH ()-[e]->() where euid(e)="4_17_5_0_0" return properties(e); +[{"properties(e)":{"_EID_":"4_17_5_0_0","_LABEL_":"ACTED_IN","charactername":"Henri Ducard"}}] +MATCH ()-[e]->() where euid(e)="4_17_5_0_0" return e.charactername; +[{"e.charactername":"Henri Ducard"}] +MATCH ()-[e]->() where euid(e)="8_13_2_0_0" set e.weight=1223 return e,labels(e),properties(e); +[{"e":{"dst":13,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 14:00:00","weight":1223.0},"src":8,"temporal_id":0},"labels(e)":"[BORN_IN]","properties(e)":"{\"_LABEL_\":\"BORN_IN\",\"_EID_\":\"8_13_2_0_0\",\"reg_time\":2023-05-01 14:00:00,\"weight\":1223.000000}"}] +MATCH ()-[e]->() where euid(e)="4_17_5_0_0" delete e; +[{"":"deleted 0 vertices, deleted 1 edges."}] diff --git a/test/resource/unit_test/edge_id_query/cypher/edge_id_query.test b/test/resource/unit_test/edge_id_query/cypher/edge_id_query.test new file mode 100644 index 0000000000..94bbb40a02 --- /dev/null +++ b/test/resource/unit_test/edge_id_query/cypher/edge_id_query.test @@ -0,0 +1,12 @@ +MATCH ()-[r]->() RETURN euid(r) /* 28 */; +MATCH ()-[r]->() RETURN id(r) /* 28 */; +MATCH (n),(m) WHERE id(n)=0 and id(m)=1 CREATE (n)-[r:ACTED_IN {charactername: "testaha"}]->(m) RETURN r; +MATCH (n),(m),(k) WHERE id(n)=0 and id(m)=2 and id(k)=3 CREATE (n)-[r:ACTED_IN {charactername: "testaha"}]->(m),(n)-[q:MARRIED]->(k) RETURN r,q; +MATCH (n)-[e]->() where id(n)=4 return euid(e); +MATCH ()-[e]->(n) where id(n)=4 return euid(e); +MATCH (n)-[e]-() where id(n)=4 return euid(e); +MATCH ()-[e]->() where euid(e)="0_2_0_0_0" return e,labels(e),properties(e); +MATCH ()-[e]->() where euid(e)="4_17_5_0_0" return properties(e); +MATCH ()-[e]->() where euid(e)="4_17_5_0_0" return e.charactername; +MATCH ()-[e]->() where euid(e)="8_13_2_0_0" set e.weight=1223 return e,labels(e),properties(e); +MATCH ()-[e]->() where euid(e)="4_17_5_0_0" delete e; \ No newline at end of file diff --git a/test/resource/unit_test/expression/cypher/expression.result b/test/resource/unit_test/expression/cypher/expression.result new file mode 100644 index 0000000000..6b79c2627d --- /dev/null +++ b/test/resource/unit_test/expression/cypher/expression.result @@ -0,0 +1,256 @@ +MATCH (n:Person {name:'Liam Neeson'}) RETURN n.birthyear, n.birthyear > 1900, n.birthyear > 2000; +[{"n.birthyear":1952,"n.birthyear > 1900":true,"n.birthyear > 2000":false}] +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE WHEN n.birthyear < 1950 THEN 1 ELSE 2 END AS type /* 2 */; +[{"type":2}] +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE WHEN n.birthyear < 1950 THEN 1 ELSE 2 END AS type1,CASE WHEN n.birthyear = 1952 THEN 1 ELSE 2 END AS type2 /* 2,1 */; +[{"type1":2,"type2":1}] +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE n.birthyear WHEN 1950 THEN 1 WHEN 1960 THEN 2 END AS type; +[{"type":null}] +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE n.birthyear WHEN 1950 THEN 1 WHEN 1960 THEN 2 ELSE 3 END AS type; +[{"type":3}] +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE n.birthyear WHEN 1952 THEN 1 WHEN 1960 THEN 2 ELSE 3 END AS type; +[{"type":1}] +MATCH (n) RETURN CASE n.name WHEN null THEN false ELSE true END AS hasName; +[{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":true},{"hasName":false},{"hasName":false},{"hasName":false},{"hasName":false},{"hasName":false}] +OPTIONAL MATCH (n {name:'Liam Neeson'}) RETURN CASE n WHEN null THEN false ELSE true END AS hasN; +[{"hasN":true}] +RETURN 2020; +[{"2020":2020}] +RETURN 1+2+3-4; +[{"1+2+3-4":2}] +RETURN 1+2 - (3+4); +[{"1+2 - (3+4)":-4}] +RETURN 1+2*3; +[{"1+2*3":7}] +RETURN (2+15)/2-3*8%10 /*4.5*/; +[{"(2+15)/2-3*8%10":4}] +WITH 2 AS a,15 AS b RETURN (a+b)/a-a*b%4; +[{"(a+b)/a-a*b%4":6}] +RETURN 2^3; +[{"2^3":8.0}] +RETURN 2^3^2; +[{"2^3^2":64.0}] +RETURN 2^(1+2)^2; +[{"2^(1+2)^2":64.0}] +RETURN 2^(1+2)*3^2-51/(8%5) /*55*/; +[{"2^(1+2)*3^2-51/(8%5)":55.0}] +RETURN 1+2.0+3+4.0; +[{"1+2.0+3+4.0":10.0}] +RETURN 1+'a'; +[{"1+'a'":"1a"}] +RETURN ['a']+'a'; +[{"['a']+'a'":"[a,a]"}] +RETURN 1+[1]; +[{"1+[1]":[1,1]}] +RETURN TRUE+[1.0]; +[{"TRUE+[1.0]":[true,1.0]}] +RETURN NULL+'a'; +[{"NULL+'a'":null}] +RETURN 1+NULL; +[{"1+NULL":null}] +RETURN 1.0-2+3.0; +[{"1.0-2+3.0":2.0}] +RETURN NULL-1.1; +[{"NULL-1.1":null}] +RETURN 1.0*2*3.0; +[{"1.0*2*3.0":6.0}] +RETURN 1.0*NULL; +[{"1.0*NULL":null}] +RETURN 1.0/2/3.0; +[{"1.0/2/3.0":0.16666666666666666}] +RETURN 1.0/NULL; +[{"1.0/NULL":null}] +RETURN 5%3; +[{"5%3":2}] +RETURN NULL%3; +[{"NULL%3":null}] +RETURN 0^0; +[{"0^0":1.0}] +RETURN null^3.0; +[{"null^3.0":null}] +RETURN 0^null; +[{"0^null":null}] +RETURN (2.0+1)*3-2/1.5+'a'+[1]; +[{"(2.0+1)*3-2/1.5+'a'+[1]":"[7.666667a,1]"}] +RETURN null^2*3/4+5-6; +[{"null^2*3/4+5-6":null}] +MATCH (n) WHERE n.name STARTS WITH 'Li' RETURN n,n.name; +[{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n.name":"Liam Neeson"},{"n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"n.name":"Lindsay Lohan"}] +MATCH (n) WHERE n.name ENDS WITH 'Redgrave' RETURN n,n.name; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"n.name":"Michael Redgrave"},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n.name":"Vanessa Redgrave"},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"n.name":"Corin Redgrave"},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n.name":"Jemma Redgrave"},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"n.name":"Roy Redgrave"}] +MATCH (n) WHERE n.name CONTAINS 'Li' RETURN n,n.name; +[{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n.name":"Liam Neeson"},{"n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"n.name":"Lindsay Lohan"}] +MATCH (n) WHERE n.name CONTAINS 'Redgrave' RETURN n,n.name; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"n.name":"Michael Redgrave"},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n.name":"Vanessa Redgrave"},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"n.name":"Corin Redgrave"},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n.name":"Jemma Redgrave"},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"n.name":"Roy Redgrave"}] +MATCH (n) WHERE n.name CONTAINS 'on' RETURN n,n.name; +[{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"n.name":"Rachel Kempson"},{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n.name":"Liam Neeson"},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n.name":"Natasha Richardson"},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"n.name":"London"},{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"n.name":"Houston"}] +MATCH (n) WHERE n.name CONTAINS 'cha' RETURN n,n.name; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"n.name":"Michael Redgrave"},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n.name":"Natasha Richardson"},{"n":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"n.name":"Richard Harris"}] +MATCH (n) WHERE n.name STARTS WITH 'Li&alonglongstring' RETURN n,n.name; +[] +MATCH (n) WHERE n.name ENDS WITH 'on&alonglongstring' RETURN n,n.name; +[] +MATCH (n) WHERE n.name CONTAINS 'on&alonglongstring' RETURN n,n.name; +[] +MATCH (n) WHERE n.name REGEXP '.*' RETURN n.name; +[{"n.name":"Rachel Kempson"},{"n.name":"Michael Redgrave"},{"n.name":"Vanessa Redgrave"},{"n.name":"Corin Redgrave"},{"n.name":"Liam Neeson"},{"n.name":"Natasha Richardson"},{"n.name":"Richard Harris"},{"n.name":"Dennis Quaid"},{"n.name":"Lindsay Lohan"},{"n.name":"Jemma Redgrave"},{"n.name":"Roy Redgrave"},{"n.name":"John Williams"},{"n.name":"Christopher Nolan"},{"n.name":"New York"},{"n.name":"London"},{"n.name":"Houston"}] +MATCH (n) WHERE n.name REGEXP 'Li.*' RETURN n.name; +[{"n.name":"Liam Neeson"},{"n.name":"Lindsay Lohan"}] +MATCH (n) WHERE n.name REGEXP '.*Redgrave' RETURN n.name; +[{"n.name":"Michael Redgrave"},{"n.name":"Vanessa Redgrave"},{"n.name":"Corin Redgrave"},{"n.name":"Jemma Redgrave"},{"n.name":"Roy Redgrave"}] +MATCH (n) WHERE n.name REGEXP 'Houston.*' RETURN n.name; +[{"n.name":"Houston"}] +MATCH (n) WHERE n.name REGEXP 'L.*on' RETURN n.name; +[{"n.name":"Liam Neeson"},{"n.name":"London"}] +MATCH (n) WHERE n.name REGEXP '.*ee.*' RETURN n.name; +[{"n.name":"Liam Neeson"}] +MATCH p = (n {name:'Rachel Kempson'})-[]->() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})<-[]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]->() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]->(m) RETURN p,m; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"m":{"identity":14,"label":"City","properties":{"name":"London"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"m":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[*1..2]->() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]}] +MATCH p = (n {name:'Rachel Kempson'})<-[*1..2]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[*1..2]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[*0..1]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[*2..3]-() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":4,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":5,"temporal_id":0},{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 11:00:00","weight":20.18},"src":5,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":19,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Liz James"},"src":5,"temporal_id":0},{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":5,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":4,"temporal_id":0},{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}},{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 11:00:00","weight":20.18},"src":5,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}},{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 12:00:00","weight":19.93},"src":12,"temporal_id":0},{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}},{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"King Arthur"},"src":6,"temporal_id":0},{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},{"dst":16,"forward":false,"identity":0,"label":"WROTE_MUSIC_FOR","label_id":4,"src":11,"temporal_id":0},{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},{"dst":16,"forward":false,"identity":0,"label":"WROTE_MUSIC_FOR","label_id":4,"src":11,"temporal_id":0},{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[*0..1]->()-[]->() RETURN p; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]-() RETURN p,length(p); +[{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}]}] +MATCH p = (n {name:'Rachel Kempson'})-[*0..3]->() RETURN p,length(p); +[{"length(p)":0,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"length(p)":1,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"length(p)":1,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"length(p)":1,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}]},{"length(p)":2,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":16,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":4,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":5,"temporal_id":0},{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 11:00:00","weight":20.18},"src":5,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},{"dst":19,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Liz James"},"src":5,"temporal_id":0},{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":5,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":14,"forward":true,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},{"identity":14,"label":"City","properties":{"name":"London"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"dst":20,"forward":true,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},{"identity":20,"label":"Film","properties":{"title":"Camelot"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},{"dst":9,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"length(p)":3,"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":0,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]}] +MATCH (n) WHERE n.name IS NULL RETURN n,label(n); +[{"label(n)":"Film","n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"label(n)":"Film","n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"label(n)":"Film","n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"label(n)":"Film","n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"label(n)":"Film","n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +MATCH (n) WHERE n.name IS NOT NULL RETURN n,label(n); +[{"label(n)":"Person","n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"label(n)":"Person","n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"label(n)":"Person","n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"label(n)":"Person","n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"label(n)":"Person","n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"label(n)":"Person","n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"label(n)":"Person","n":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}}},{"label(n)":"Person","n":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}},{"label(n)":"Person","n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}}},{"label(n)":"Person","n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"label(n)":"Person","n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"label(n)":"Person","n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}}},{"label(n)":"Person","n":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"label(n)":"City","n":{"identity":13,"label":"City","properties":{"name":"New York"}}},{"label(n)":"City","n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"label(n)":"City","n":{"identity":15,"label":"City","properties":{"name":"Houston"}}}] +MATCH (n) WHERE n.name IS NOT NULL AND n.birthyear IS NULL RETURN n,label(n); +[{"label(n)":"City","n":{"identity":13,"label":"City","properties":{"name":"New York"}}},{"label(n)":"City","n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"label(n)":"City","n":{"identity":15,"label":"City","properties":{"name":"Houston"}}}] +MATCH (n) RETURN n.name, CASE WHEN n.birthyear IS NULL THEN -1 ELSE n.birthyear + 10 END AS birth_10_years_later; +[{"birth_10_years_later":1920,"n.name":"Rachel Kempson"},{"birth_10_years_later":1918,"n.name":"Michael Redgrave"},{"birth_10_years_later":1947,"n.name":"Vanessa Redgrave"},{"birth_10_years_later":1949,"n.name":"Corin Redgrave"},{"birth_10_years_later":1962,"n.name":"Liam Neeson"},{"birth_10_years_later":1973,"n.name":"Natasha Richardson"},{"birth_10_years_later":1940,"n.name":"Richard Harris"},{"birth_10_years_later":1964,"n.name":"Dennis Quaid"},{"birth_10_years_later":1996,"n.name":"Lindsay Lohan"},{"birth_10_years_later":1975,"n.name":"Jemma Redgrave"},{"birth_10_years_later":1883,"n.name":"Roy Redgrave"},{"birth_10_years_later":1942,"n.name":"John Williams"},{"birth_10_years_later":1980,"n.name":"Christopher Nolan"},{"birth_10_years_later":-1,"n.name":"New York"},{"birth_10_years_later":-1,"n.name":"London"},{"birth_10_years_later":-1,"n.name":"Houston"},{"birth_10_years_later":-1,"n.name":null},{"birth_10_years_later":-1,"n.name":null},{"birth_10_years_later":-1,"n.name":null},{"birth_10_years_later":-1,"n.name":null},{"birth_10_years_later":-1,"n.name":null}] +MATCH (n) WHERE exists(n.title) RETURN n.title,n; +[{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n.title":"Goodbye, Mr. Chips"},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n.title":"Batman Begins"},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n.title":"Harry Potter and the Sorcerer's Stone"},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"}] +MATCH (n) RETURN exists(n.name) AS has_name,exists(n.title) AS has_title,label(n); +[{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"Person"},{"has_name":true,"has_title":false,"label(n)":"City"},{"has_name":true,"has_title":false,"label(n)":"City"},{"has_name":true,"has_title":false,"label(n)":"City"},{"has_name":false,"has_title":true,"label(n)":"Film"},{"has_name":false,"has_title":true,"label(n)":"Film"},{"has_name":false,"has_title":true,"label(n)":"Film"},{"has_name":false,"has_title":true,"label(n)":"Film"},{"has_name":false,"has_title":true,"label(n)":"Film"}] +MATCH (n) RETURN n,CASE exists(n.name) WHEN true THEN n.name ELSE n.title END AS content; +[{"content":"Rachel Kempson","n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"content":"Michael Redgrave","n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"content":"Vanessa Redgrave","n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"content":"Corin Redgrave","n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"content":"Liam Neeson","n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"content":"Natasha Richardson","n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"content":"Richard Harris","n":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}}},{"content":"Dennis Quaid","n":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}},{"content":"Lindsay Lohan","n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}}},{"content":"Jemma Redgrave","n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"content":"Roy Redgrave","n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"content":"John Williams","n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}}},{"content":"Christopher Nolan","n":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"content":"New York","n":{"identity":13,"label":"City","properties":{"name":"New York"}}},{"content":"London","n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"content":"Houston","n":{"identity":15,"label":"City","properties":{"name":"Houston"}}},{"content":"Goodbye, Mr. Chips","n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"content":"Batman Begins","n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"content":"Harry Potter and the Sorcerer's Stone","n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"content":"The Parent Trap","n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"content":"Camelot","n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[]->()) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[]->(:Person)) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[]->(:City)) /*false*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":false}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:NO_TYPE]->()) /*false*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":false}] +MATCH (n {name:'Rachel Kempson'}),(m {name:'Liam Neeson'}) RETURN exists((n)-[]->(m)) /*false*/; +[{"{EXISTS(NestedPattern(n,m))}":false}] +MATCH (n {name:'Rachel Kempson'}),(m {name:'Liam Neeson'}) RETURN NOT exists((n)-[]->(m)) AS isNew /*true*/; +[{"isNew":true}] +MATCH (n {name:'Rachel Kempson'}),(m {name:'Michael Redgrave'}) RETURN exists((n)-[]->(m)) /*true*/; +[{"{EXISTS(NestedPattern(n,m))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()-[]->()) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1,@ANON_N3))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()-[:ACTED_IN]->()) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1,@ANON_N3))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()-[:BORN_IN]->()) /*false*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1,@ANON_N3))}":false}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[*3]->()) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":true}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED*3]->()) /*false*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":false}] +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED|HAS_CHILD*3]->()) /*true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1))}":true}] +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[]->(m)) /*3 true*/; +[{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":true},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":true},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":true}] +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[:MARRIED]->(m)) /*1 true*/; +[{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":true},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false},{"{EXISTS(NestedPattern(n,m))}":false}] +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[:MARRIED]->()-[]->(m)) /*3 true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":true},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":true},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":true}] +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[:HAS_CHILD]->()-[]->(m)) /*2 true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":true},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":true},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false}] +MATCH (n {name:'Rachel Kempson'}),(m:City) RETURN exists((n)-[:HAS_CHILD]->()-[:BORN_IN]->(m)) /*1 true*/; +[{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":true},{"{EXISTS(NestedPattern(n,@ANON_N1,m))}":false}] +MATCH (n:Person)-[:BORN_IN]->(c) WHERE exists((n)-[:HAS_CHILD]->()-[:BORN_IN]->(c)) RETURN n,c; +[{"c":{"identity":14,"label":"City","properties":{"name":"London"}},"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +RETURN [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] AS list; +[{"list":[0,1,2,3,4,5,6,7,8,9]}] +WITH [1,3,5,7] AS a RETURN a; +[{"a":[1,3,5,7]}] +RETURN range(0, 4), range(2, 18, 3) /* [0,1,2,3,4],[2,5,8,11,14,17] */; +[{"range(0, 4)":[0,1,2,3,4],"range(2, 18, 3)":[2,5,8,11,14,17]}] +RETURN range(0, 10)[3]; +[{"range(0, 10)[3]":3}] +RETURN range(0, 10)[-3] /* 8 */; +[{"range(0, 10)[-3]":8}] +RETURN range(0, 10)[15]; +[{"range(0, 10)[15]":null}] +RETURN range(0, 10)[0..3]; +[{"range(0, 10)[0..3]":[0,1,2]}] +RETURN range(0, 10)[0..-5] /* [0,1,2,3,4,5] */; +[{"range(0, 10)[0..-5]":[0,1,2,3,4,5]}] +RETURN range(0, 10)[3..3] /* [] */; +[{"range(0, 10)[3..3]":[]}] +RETURN range(0, 10)[3..1] /* [] */; +[{"range(0, 10)[3..1]":[]}] +RETURN [1,2,3,4,5]+[6,7] AS myList; +[{"myList":[1,2,3,4,5,6,7]}] +WITH [1,2,3,4,5] AS l1, [6,7] AS l2 RETURN l1+l2 AS myList; +[{"myList":[1,2,3,4,5,6,7]}] +MATCH (n:City) RETURN collect(n.name)+['Wuhan'] AS cNames; +[{"cNames":"[Houston,London,New York,Wuhan]"}] +UNWIND [2, 3, 4, 5] AS number WITH number WHERE number IN [2, 3, 8] RETURN number; +[{"number":2},{"number":3}] +RETURN date('2017-05-03'); +[{"date('2017-05-03')":"2017-05-03"}] +RETURN date('2017-05-01'); +[{"date('2017-05-01')":"2017-05-01"}] +RETURN date('2017-05-01') < date('2017-05-03'); +[{"date('2017-05-01') < date('2017-05-03')":true}] +RETURN date('2017-05-03') > date('2017-05-01'); +[{"date('2017-05-03') > date('2017-05-01')":true}] +RETURN date('2017-05-01') = date('2017-05-01'); +[{"date('2017-05-01') = date('2017-05-01')":true}] +RETURN datetime('2017-05-03 10:40:32') AS timePoint; +[{"timePoint":"2017-05-03 10:40:32"}] +RETURN datetime('2017-05-01 10:00:00') > datetime('2017-05-03 08:00:00'); +[{"datetime('2017-05-01 10:00:00') > datetime('2017-05-03 08:00:00')":false}] +RETURN datetime('2017-05-01 10:00:00') < datetime('2017-05-03 08:00:00'); +[{"datetime('2017-05-01 10:00:00') < datetime('2017-05-03 08:00:00')":true}] +RETURN datetime('2017-05-01 10:00:00.000001') > datetime('2017-05-01 10:00:00'); +[{"datetime('2017-05-01 10:00:00.000001') > datetime('2017-05-01 10:00:00')":true}] +RETURN datetime('2017-05-01 10:00:00.000002') > datetime('2017-05-01 10:00:00.000001'); +[{"datetime('2017-05-01 10:00:00.000002') > datetime('2017-05-01 10:00:00.000001')":true}] +WITH datetime('2017-05-01 10:00:00') AS t1, datetime('2017-05-03 08:00:00') AS t2 RETURN t1>t2,t1t2":false}] +WITH true AS bt, false AS bf RETURN bt = false, bf = false, bt <> bf; +[{"bf = false":true,"bt <> bf":true,"bt = false":false}] +RETURN bin('MjAyMAo=') > bin('MjAxOQo='); +[{"bin('MjAyMAo=') > bin('MjAxOQo=')":true}] +RETURN bin('MjAyMAo=') < bin('MjAxOQo='); +[{"bin('MjAyMAo=') < bin('MjAxOQo=')":false}] +RETURN bin('MjAyMAo=') = bin('MjAyMAo='); +[{"bin('MjAyMAo=') = bin('MjAyMAo=')":true}] +WITH bin('MjAyMAo=') AS bin1, bin('MjAxOQo=') AS bin2 RETURN bin1>bin2,bin1bin2":true}] +RETURN dateComponent(12345, 'year'), datetimeComponent(12345, 'month'), datetimeComponent(12345, 'day'); +[{"dateComponent(12345, 'year')":2003,"datetimeComponent(12345, 'day')":1,"datetimeComponent(12345, 'month')":1}] +RETURN datetimeComponent(1582705717, 'year'),datetimeComponent(1582705717, 'month'),datetimeComponent(1582705717, 'day'); +[{"datetimeComponent(1582705717, 'day')":1,"datetimeComponent(1582705717, 'month')":1,"datetimeComponent(1582705717, 'year')":1970}] +RETURN datetimeComponent(1582705717, 'hour'),datetimeComponent(1582705717, 'minute'),datetimeComponent(1582705717, 'second'), datetimeComponent(1582705717, 'microsecond'); +[{"datetimeComponent(1582705717, 'hour')":0,"datetimeComponent(1582705717, 'microsecond')":705717,"datetimeComponent(1582705717, 'minute')":26,"datetimeComponent(1582705717, 'second')":22}] +RETURN datetimeComponent(1582705717000, 'year'),datetimeComponent(1582705717000, 'second'), datetimeComponent(1582705717000, 'microsecond'); +[{"datetimeComponent(1582705717000, 'microsecond')":717000,"datetimeComponent(1582705717000, 'second')":25,"datetimeComponent(1582705717000, 'year')":1970}] diff --git a/test/resource/unit_test/expression/cypher/expression.test b/test/resource/unit_test/expression/cypher/expression.test new file mode 100644 index 0000000000..665c498351 --- /dev/null +++ b/test/resource/unit_test/expression/cypher/expression.test @@ -0,0 +1,128 @@ +MATCH (n:Person {name:'Liam Neeson'}) RETURN n.birthyear, n.birthyear > 1900, n.birthyear > 2000; +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE WHEN n.birthyear < 1950 THEN 1 ELSE 2 END AS type /* 2 */; +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE WHEN n.birthyear < 1950 THEN 1 ELSE 2 END AS type1,CASE WHEN n.birthyear = 1952 THEN 1 ELSE 2 END AS type2 /* 2,1 */; +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE n.birthyear WHEN 1950 THEN 1 WHEN 1960 THEN 2 END AS type; +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE n.birthyear WHEN 1950 THEN 1 WHEN 1960 THEN 2 ELSE 3 END AS type; +MATCH (n:Person {name:'Liam Neeson'}) RETURN CASE n.birthyear WHEN 1952 THEN 1 WHEN 1960 THEN 2 ELSE 3 END AS type; +MATCH (n) RETURN CASE n.name WHEN null THEN false ELSE true END AS hasName; +OPTIONAL MATCH (n {name:'Liam Neeson'}) RETURN CASE n WHEN null THEN false ELSE true END AS hasN; +RETURN 2020; +RETURN 1+2+3-4; +RETURN 1+2 - (3+4); +RETURN 1+2*3; +RETURN (2+15)/2-3*8%10 /*4.5*/; +WITH 2 AS a,15 AS b RETURN (a+b)/a-a*b%4; +RETURN 2^3; +RETURN 2^3^2; +RETURN 2^(1+2)^2; +RETURN 2^(1+2)*3^2-51/(8%5) /*55*/; +RETURN 1+2.0+3+4.0; +RETURN 1+'a'; +RETURN ['a']+'a'; +RETURN 1+[1]; +RETURN TRUE+[1.0]; +RETURN NULL+'a'; +RETURN 1+NULL; +RETURN 1.0-2+3.0; +RETURN NULL-1.1; +RETURN 1.0*2*3.0; +RETURN 1.0*NULL; +RETURN 1.0/2/3.0; +RETURN 1.0/NULL; +RETURN 5%3; +RETURN NULL%3; +RETURN 0^0; +RETURN null^3.0; +RETURN 0^null; +RETURN (2.0+1)*3-2/1.5+'a'+[1]; +RETURN null^2*3/4+5-6; +MATCH (n) WHERE n.name STARTS WITH 'Li' RETURN n,n.name; +MATCH (n) WHERE n.name ENDS WITH 'Redgrave' RETURN n,n.name; +MATCH (n) WHERE n.name CONTAINS 'Li' RETURN n,n.name; +MATCH (n) WHERE n.name CONTAINS 'Redgrave' RETURN n,n.name; +MATCH (n) WHERE n.name CONTAINS 'on' RETURN n,n.name; +MATCH (n) WHERE n.name CONTAINS 'cha' RETURN n,n.name; +MATCH (n) WHERE n.name STARTS WITH 'Li&alonglongstring' RETURN n,n.name; +MATCH (n) WHERE n.name ENDS WITH 'on&alonglongstring' RETURN n,n.name; +MATCH (n) WHERE n.name CONTAINS 'on&alonglongstring' RETURN n,n.name; +MATCH (n) WHERE n.name REGEXP '.*' RETURN n.name; +MATCH (n) WHERE n.name REGEXP 'Li.*' RETURN n.name; +MATCH (n) WHERE n.name REGEXP '.*Redgrave' RETURN n.name; +MATCH (n) WHERE n.name REGEXP 'Houston.*' RETURN n.name; +MATCH (n) WHERE n.name REGEXP 'L.*on' RETURN n.name; +MATCH (n) WHERE n.name REGEXP '.*ee.*' RETURN n.name; +MATCH p = (n {name:'Rachel Kempson'})-[]->() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})<-[]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]->() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]->(m) RETURN p,m; +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[*1..2]->() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})<-[*1..2]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[*1..2]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[*0..1]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[*2..3]-() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[*0..1]->()-[]->() RETURN p; +MATCH p = (n {name:'Rachel Kempson'})-[]->()-[]-() RETURN p,length(p); +MATCH p = (n {name:'Rachel Kempson'})-[*0..3]->() RETURN p,length(p); +MATCH (n) WHERE n.name IS NULL RETURN n,label(n); +MATCH (n) WHERE n.name IS NOT NULL RETURN n,label(n); +MATCH (n) WHERE n.name IS NOT NULL AND n.birthyear IS NULL RETURN n,label(n); +MATCH (n) RETURN n.name, CASE WHEN n.birthyear IS NULL THEN -1 ELSE n.birthyear + 10 END AS birth_10_years_later; +MATCH (n) WHERE exists(n.title) RETURN n.title,n; +MATCH (n) RETURN exists(n.name) AS has_name,exists(n.title) AS has_title,label(n); +MATCH (n) RETURN n,CASE exists(n.name) WHEN true THEN n.name ELSE n.title END AS content; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[]->()) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[]->(:Person)) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[]->(:City)) /*false*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:NO_TYPE]->()) /*false*/; +MATCH (n {name:'Rachel Kempson'}),(m {name:'Liam Neeson'}) RETURN exists((n)-[]->(m)) /*false*/; +MATCH (n {name:'Rachel Kempson'}),(m {name:'Liam Neeson'}) RETURN NOT exists((n)-[]->(m)) AS isNew /*true*/; +MATCH (n {name:'Rachel Kempson'}),(m {name:'Michael Redgrave'}) RETURN exists((n)-[]->(m)) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()-[]->()) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()-[:ACTED_IN]->()) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED]->()-[:BORN_IN]->()) /*false*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[*3]->()) /*true*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED*3]->()) /*false*/; +MATCH (n {name:'Rachel Kempson'}) RETURN exists((n)-[:MARRIED|HAS_CHILD*3]->()) /*true*/; +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[]->(m)) /*3 true*/; +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[:MARRIED]->(m)) /*1 true*/; +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[:MARRIED]->()-[]->(m)) /*3 true*/; +MATCH (n {name:'Rachel Kempson'}),(m:Person) RETURN exists((n)-[:HAS_CHILD]->()-[]->(m)) /*2 true*/; +MATCH (n {name:'Rachel Kempson'}),(m:City) RETURN exists((n)-[:HAS_CHILD]->()-[:BORN_IN]->(m)) /*1 true*/; +MATCH (n:Person)-[:BORN_IN]->(c) WHERE exists((n)-[:HAS_CHILD]->()-[:BORN_IN]->(c)) RETURN n,c; +RETURN [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] AS list; +WITH [1,3,5,7] AS a RETURN a; +RETURN range(0, 4), range(2, 18, 3) /* [0,1,2,3,4],[2,5,8,11,14,17] */; +RETURN range(0, 10)[3]; +RETURN range(0, 10)[-3] /* 8 */; +RETURN range(0, 10)[15]; +RETURN range(0, 10)[0..3]; +RETURN range(0, 10)[0..-5] /* [0,1,2,3,4,5] */; +RETURN range(0, 10)[3..3] /* [] */; +RETURN range(0, 10)[3..1] /* [] */; +RETURN [1,2,3,4,5]+[6,7] AS myList; +WITH [1,2,3,4,5] AS l1, [6,7] AS l2 RETURN l1+l2 AS myList; +MATCH (n:City) RETURN collect(n.name)+['Wuhan'] AS cNames; +UNWIND [2, 3, 4, 5] AS number WITH number WHERE number IN [2, 3, 8] RETURN number; +RETURN date('2017-05-03'); +RETURN date('2017-05-01'); +RETURN date('2017-05-01') < date('2017-05-03'); +RETURN date('2017-05-03') > date('2017-05-01'); +RETURN date('2017-05-01') = date('2017-05-01'); +RETURN datetime('2017-05-03 10:40:32') AS timePoint; +RETURN datetime('2017-05-01 10:00:00') > datetime('2017-05-03 08:00:00'); +RETURN datetime('2017-05-01 10:00:00') < datetime('2017-05-03 08:00:00'); +RETURN datetime('2017-05-01 10:00:00.000001') > datetime('2017-05-01 10:00:00'); +RETURN datetime('2017-05-01 10:00:00.000002') > datetime('2017-05-01 10:00:00.000001'); +WITH datetime('2017-05-01 10:00:00') AS t1, datetime('2017-05-03 08:00:00') AS t2 RETURN t1>t2,t1 bf; +RETURN bin('MjAyMAo=') > bin('MjAxOQo='); +RETURN bin('MjAyMAo=') < bin('MjAxOQo='); +RETURN bin('MjAyMAo=') = bin('MjAyMAo='); +WITH bin('MjAyMAo=') AS bin1, bin('MjAxOQo=') AS bin2 RETURN bin1>bin2,bin1= 1960 AND post60s.birthyear < 1970 RETURN post60s.name; +[{"post60s.name":"Jemma Redgrave"},{"post60s.name":"Natasha Richardson"}] +MATCH (a:Person) WHERE a.birthyear < 1960 OR a.birthyear >= 1970 RETURN a.name; +[{"a.name":"Christopher Nolan"},{"a.name":"Corin Redgrave"},{"a.name":"Dennis Quaid"},{"a.name":"John Williams"},{"a.name":"Liam Neeson"},{"a.name":"Lindsay Lohan"},{"a.name":"Michael Redgrave"},{"a.name":"Rachel Kempson"},{"a.name":"Richard Harris"},{"a.name":"Roy Redgrave"},{"a.name":"Vanessa Redgrave"}] +MATCH (a:Person) WHERE a.birthyear >= 1960 XOR id(a) > 10 RETURN a,a.birthyear; +[{"a":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"a.birthyear":1965},{"a":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"a.birthyear":1932},{"a":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"a.birthyear":1986},{"a":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"a.birthyear":1963}] +MATCH (n {name:'Vanessa Redgrave'}) RETURN n; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (n:Person)-[r:BORN_IN]->() WHERE abs(r.weight-20.21)<0.00001 RETURN n,r,r.weight; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},"r.weight":20.21}] diff --git a/test/resource/unit_test/find/cypher/find.test b/test/resource/unit_test/find/cypher/find.test new file mode 100644 index 0000000000..ebc72eb63d --- /dev/null +++ b/test/resource/unit_test/find/cypher/find.test @@ -0,0 +1,11 @@ + +MATCH (n:Person {name:'Vanessa Redgrave'}) RETURN n; +MATCH (m:Film {title:'The Parent Trap'}) RETURN m.title,m; +MATCH (people:Person) RETURN people.name LIMIT 7; +MATCH (people:Person) RETURN people.name SKIP 7; +MATCH (people:Person) RETURN people.name SKIP 3 LIMIT 4; +MATCH (post60s:Person) WHERE post60s.birthyear >= 1960 AND post60s.birthyear < 1970 RETURN post60s.name; +MATCH (a:Person) WHERE a.birthyear < 1960 OR a.birthyear >= 1970 RETURN a.name; +MATCH (a:Person) WHERE a.birthyear >= 1960 XOR id(a) > 10 RETURN a,a.birthyear; +MATCH (n {name:'Vanessa Redgrave'}) RETURN n; +MATCH (n:Person)-[r:BORN_IN]->() WHERE abs(r.weight-20.21)<0.00001 RETURN n,r,r.weight; diff --git a/test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.result b/test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.result new file mode 100644 index 0000000000..5f6c58cee1 --- /dev/null +++ b/test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.result @@ -0,0 +1,84 @@ +MATCH (n:Person {name:'Liam Neeson'}) WITH n AS aa RETURN aa.name; +[{"aa.name":"Liam Neeson"}] +MATCH (n:Person {name:'Liam Neeson'})-[e]->(m) WITH e AS aa RETURN aa; +[{"aa":{"dst":5,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":4,"temporal_id":0}},{"aa":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0}}] +MATCH (n:Person {name:'Liam Neeson'}) SET n.birthyear=2052 RETURN n.birthyear; +[{"n.birthyear":2052}] +MATCH (n:Person {name:'Liam Neeson'}),(m:Person {name:'Richard Harris'}) SET n.birthyear=2152 RETURN n.birthyear,m.birthyear /*2152,1930*/; +[{"m.birthyear":1930,"n.birthyear":2152}] +MATCH (n:Person {name:'Liam Neeson'}),(m:Person {name:'Richard Harris'}) SET n.birthyear=2252,m.birthyear=2230 RETURN n.birthyear,m.birthyear /*2252,2230*/; +[{"m.birthyear":2230,"n.birthyear":2252}] +MERGE (z3:Person {name:'zhang3'}) ON CREATE SET z3.birthyear=2021 ON MATCH SET z3.birthyear=2022 WITH z3 MERGE (z4:Person {name:'zhang4'}) ON CREATE SET z4.birthyear=2021 ON MATCH SET z4.birthyear=2022 WITH z3,z4 CREATE (z3)-[:HAS_CHILD]->(z4); +[{"":"created 2 vertices, created 1 edges."}] +MATCH (z3:Person {name:'zhang3'})-[r]->(z4:Person {name:'zhang4'}) RETURN r; +[{"r":{"dst":22,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":21,"temporal_id":0}}] +MERGE (z3:Person {name:'zhang3'}) ON CREATE SET z3.birthyear=2021 ON MATCH SET z3.birthyear=2022 WITH z3 MERGE (z4:Person {name:'zhang4'}) ON CREATE SET z4.birthyear=2021 ON MATCH SET z4.birthyear=2022 WITH z3,z4 CREATE (z3)-[r:HAS_CHILD]->(z4) RETURN z3,z4,r; +[{"r":{"dst":22,"forward":false,"identity":1,"label":"HAS_CHILD","label_id":0,"src":21,"temporal_id":0},"z3":{"identity":21,"label":"Person","properties":{"birthyear":2022,"name":"zhang3"}},"z4":{"identity":22,"label":"Person","properties":{"birthyear":2022,"name":"zhang4"}}}] +MATCH (z3:Person {name:'zhang3'})-[r]->(z4:Person {name:'zhang4'}) RETURN r; +[{"r":{"dst":22,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":21,"temporal_id":0}},{"r":{"dst":22,"forward":false,"identity":1,"label":"HAS_CHILD","label_id":0,"src":21,"temporal_id":0}}] +MATCH (m:City) RETURN collect(m.name) + [1,2]; +[{"collect(m.name) + [1,2]":"[Houston,London,New York,1,2]"}] +WITH [1,2] AS nn MATCH (m:City) RETURN collect(m.name) + nn; +[{"collect(expr::prop = {m.name}),nn,\"+\"":"[New York,London,Houston,1,2]"}] +MATCH (n:City) WITH collect(n.name) AS nn MATCH (m:City) RETURN collect(m.name) + nn; +[{"collect(expr::prop = {m.name}),nn,\"+\"":"[New York,London,Houston,Houston,London,New York]"}] +MATCH (n:Person) RETURN -n.birthyear LIMIT 3; +[{"0,expr::prop = {n.birthyear},\"-\"":-1970},{"0,expr::prop = {n.birthyear},\"-\"":-1939},{"0,expr::prop = {n.birthyear},\"-\"":-1954}] +MATCH (n:Person) RETURN -sum(n.birthyear) /*-27241*/; +[{"0,sum(expr::prop = {n.birthyear}),\"-\"":-29863.0}] +MATCH (n) -[r:HAS_CHILD * 2 ]->(m) RETURN n,m ; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (n) -[r:HAS_CHILD * .. ]->(m) RETURN n,m ; +[{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":22,"label":"Person","properties":{"birthyear":2022,"name":"zhang4"}},"n":{"identity":21,"label":"Person","properties":{"birthyear":2022,"name":"zhang3"}}},{"m":{"identity":22,"label":"Person","properties":{"birthyear":2022,"name":"zhang4"}},"n":{"identity":21,"label":"Person","properties":{"birthyear":2022,"name":"zhang3"}}}] +WITH '1' as s UNWIND ['a','b'] as k RETURN s,k; +[{"k":"a","s":"1"},{"k":"b","s":"1"}] +WITH '1' as s UNWIND ['a','b']+s as k RETURN s,k; +[{"k":"a","s":"1"},{"k":"b","s":"1"},{"k":"1","s":"1"}] +MATCH (n:Person)-[]->(m:Film) WITH n.name AS nname, collect(id(m)) AS mc MATCH (n:Person {name: nname})<-[]-(o) WITH n.name AS nname, mc, collect(id(o)) AS oc UNWIND mc+oc AS c RETURN c; +[{"c":16},{"c":10},{"c":0},{"c":17},{"c":5},{"c":20},{"c":0},{"c":1},{"c":19},{"c":2},{"c":4}] +MATCH (m:Person)-[r:BORN_IN]->(n:City) WHERE n.name = 'London' and r.weight >= 1 and r.weight <= 100 RETURN sum(r.weight); +[{"sum(r.weight)":60.31999969482422}] +MATCH (n:City) RETURN collect(n.name) + n.name; +[CypherException] CypherException: Function not implemented yet: HandOff at src/cypher/execution_plan/ops/op_aggregate.cpp:124 +MATCH (n:Person) RETURN NOT n.nam; +[ParserException] ParserException: Type error +MATCH (n:Person) RETURN -n.name; +[CypherException] CypherException: Type mismatch: expect Integer or Float in sub expr +REMOVE a.name; +[InputError] Variable `a` not defined +SET a :MyLabel; +[InputError] Variable `a` not defined +MATCH (n:Person) WITH n,n.name RETURN n.name; +[ParserException] ParserException: Non-variable expression in WITH must be aliased +WITH * MERGE(n:Person) RETURN n; +[CypherException] CypherException: WITH * syntax is not implemented now +RETURN * UNION RETURN *; +[CypherException] CypherException: All sub queries in an UNION must have the same column names. +RETURN * UNION RETURN 1 AS a; +[CypherException] CypherException: All sub queries in an UNION must have the same column names. +RETURN 2 AS b UNION RETURN 1 AS a; +[CypherException] CypherException: All sub queries in an UNION must have the same column names. +RETURN 2 AS b UNION RETURN 1 AS a, 3 AS c; +[CypherException] CypherException: All sub queries in an UNION must have the same column names. +DELETE []; +[InputError] Type mismatch: expected Node, Path or Relationship +DELETE [x in [1, 2, 3] | x]; +[InputError] Type mismatch: expected Node, Path or Relationship +DELETE TRUE; +[InputError] Type mismatch: expected Node, Path or Relationship +MERGE (n:null {id: 2909}) RETURN n; +[CypherException] CypherException: cannot match node with given label and properties +MATCH (n:Person {name:'Liam Neeson'}), (m:Person {name:'Liam Neeson'}), (o:Person {name:'Liam Neeson'}) WHERE custom.myadd('asd')='1' RETURN 1; +[InputError] Plugin [_fma_myadd] does not exist. +MATCH (movie)<-[r]-(n) WITH n,n MATCH (n1) RETURN n1 LIMIT 1; +[CypherException] CypherException: Duplicate alias: n +MATCH (movie)<-[r]-(n) return n,n limit 1; +[CypherException] CypherException: Duplicate alias: n +MATCH (n) RETURN n LIMIT 5; +[{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":4,"label":"Person","properties":{"birthyear":2252,"name":"Liam Neeson"}}}] +CALL db.vertexLabels; +[{"label":"Person"},{"label":"City"},{"label":"Film"}] +CALL dbms.graph.listGraphs(); +[{"configuration":{"description":"","max_size_GB":4096},"graph_name":"default"}] +MATCH p=(n)-[e]->(m) RETURN p LIMIT 5; +[{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]},{"p":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]},{"p":[{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}]},{"p":[{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}]}] diff --git a/test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.test b/test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.test new file mode 100644 index 0000000000..6f3e264d8b --- /dev/null +++ b/test/resource/unit_test/fix_crash_issues/cypher/fix_crash_issues.test @@ -0,0 +1,42 @@ +MATCH (n:Person {name:'Liam Neeson'}) WITH n AS aa RETURN aa.name; +MATCH (n:Person {name:'Liam Neeson'})-[e]->(m) WITH e AS aa RETURN aa; +MATCH (n:Person {name:'Liam Neeson'}) SET n.birthyear=2052 RETURN n.birthyear; +MATCH (n:Person {name:'Liam Neeson'}),(m:Person {name:'Richard Harris'}) SET n.birthyear=2152 RETURN n.birthyear,m.birthyear /*2152,1930*/; +MATCH (n:Person {name:'Liam Neeson'}),(m:Person {name:'Richard Harris'}) SET n.birthyear=2252,m.birthyear=2230 RETURN n.birthyear,m.birthyear /*2252,2230*/; +MERGE (z3:Person {name:'zhang3'}) ON CREATE SET z3.birthyear=2021 ON MATCH SET z3.birthyear=2022 WITH z3 MERGE (z4:Person {name:'zhang4'}) ON CREATE SET z4.birthyear=2021 ON MATCH SET z4.birthyear=2022 WITH z3,z4 CREATE (z3)-[:HAS_CHILD]->(z4); +MATCH (z3:Person {name:'zhang3'})-[r]->(z4:Person {name:'zhang4'}) RETURN r; +MERGE (z3:Person {name:'zhang3'}) ON CREATE SET z3.birthyear=2021 ON MATCH SET z3.birthyear=2022 WITH z3 MERGE (z4:Person {name:'zhang4'}) ON CREATE SET z4.birthyear=2021 ON MATCH SET z4.birthyear=2022 WITH z3,z4 CREATE (z3)-[r:HAS_CHILD]->(z4) RETURN z3,z4,r; +MATCH (z3:Person {name:'zhang3'})-[r]->(z4:Person {name:'zhang4'}) RETURN r; +MATCH (m:City) RETURN collect(m.name) + [1,2]; +WITH [1,2] AS nn MATCH (m:City) RETURN collect(m.name) + nn; +MATCH (n:City) WITH collect(n.name) AS nn MATCH (m:City) RETURN collect(m.name) + nn; +MATCH (n:Person) RETURN -n.birthyear LIMIT 3; +MATCH (n:Person) RETURN -sum(n.birthyear) /*-27241*/; +MATCH (n) -[r:HAS_CHILD * 2 ]->(m) RETURN n,m ; +MATCH (n) -[r:HAS_CHILD * .. ]->(m) RETURN n,m ; +WITH '1' as s UNWIND ['a','b'] as k RETURN s,k; +WITH '1' as s UNWIND ['a','b']+s as k RETURN s,k; +MATCH (n:Person)-[]->(m:Film) WITH n.name AS nname, collect(id(m)) AS mc MATCH (n:Person {name: nname})<-[]-(o) WITH n.name AS nname, mc, collect(id(o)) AS oc UNWIND mc+oc AS c RETURN c; +MATCH (m:Person)-[r:BORN_IN]->(n:City) WHERE n.name = 'London' and r.weight >= 1 and r.weight <= 100 RETURN sum(r.weight); +MATCH (n:City) RETURN collect(n.name) + n.name; +MATCH (n:Person) RETURN NOT n.nam; +MATCH (n:Person) RETURN -n.name; +REMOVE a.name; +SET a :MyLabel; +MATCH (n:Person) WITH n,n.name RETURN n.name; +WITH * MERGE(n:Person) RETURN n; +RETURN * UNION RETURN *; +RETURN * UNION RETURN 1 AS a; +RETURN 2 AS b UNION RETURN 1 AS a; +RETURN 2 AS b UNION RETURN 1 AS a, 3 AS c; +DELETE []; +DELETE [x in [1, 2, 3] | x]; +DELETE TRUE; +MERGE (n:null {id: 2909}) RETURN n; +MATCH (n:Person {name:'Liam Neeson'}), (m:Person {name:'Liam Neeson'}), (o:Person {name:'Liam Neeson'}) WHERE custom.myadd('asd')='1' RETURN 1; +MATCH (movie)<-[r]-(n) WITH n,n MATCH (n1) RETURN n1 LIMIT 1; +MATCH (movie)<-[r]-(n) return n,n limit 1; +MATCH (n) RETURN n LIMIT 5; +CALL db.vertexLabels; +CALL dbms.graph.listGraphs(); +MATCH p=(n)-[e]->(m) RETURN p LIMIT 5; diff --git a/test/resource/unit_test/func_filter/cypher/func_filter.result b/test/resource/unit_test/func_filter/cypher/func_filter.result new file mode 100644 index 0000000000..29979b9922 --- /dev/null +++ b/test/resource/unit_test/func_filter/cypher/func_filter.result @@ -0,0 +1,9 @@ +MATCH (n) WHERE id(n) = 6 RETURN n.name; +[{"n.name":"Richard Harris"}] +MATCH (n) WHERE id(n) <> 6 RETURN n; +[{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}},{"n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}}},{"n":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"n":{"identity":13,"label":"City","properties":{"name":"New York"}}},{"n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}}},{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +MATCH ()-[r]->() WHERE type(r) = 'ACTED_IN' RETURN r,type(r); +[{"r":{"dst":16,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Liz James"},"src":5,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":18,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Albus Dumbledore"},"src":6,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"King Arthur"},"src":6,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Nick Parker"},"src":7,"temporal_id":0},"type(r)":"ACTED_IN"},{"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Halle/Annie"},"src":8,"temporal_id":0},"type(r)":"ACTED_IN"}] +#MATCH ()-[r]->() WHERE type(4) = 'ACTED_IN' RETURN r,type(r) /* invalid argument */; +MATCH (a)-->(b)-->(c)<--(d) WHERE id(b) <> id(d) AND id(a) > id(d) AND id(b) < id(c) RETURN a,b,c,d; +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"c":{"identity":14,"label":"City","properties":{"name":"London"}},"d":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"a":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"b":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"c":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"d":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"a":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"b":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"c":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"d":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"a":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"b":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"c":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"d":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}}] diff --git a/test/resource/unit_test/func_filter/cypher/func_filter.test b/test/resource/unit_test/func_filter/cypher/func_filter.test new file mode 100644 index 0000000000..6c75d196dd --- /dev/null +++ b/test/resource/unit_test/func_filter/cypher/func_filter.test @@ -0,0 +1,5 @@ +MATCH (n) WHERE id(n) = 6 RETURN n.name; +MATCH (n) WHERE id(n) <> 6 RETURN n; +MATCH ()-[r]->() WHERE type(r) = 'ACTED_IN' RETURN r,type(r); +#MATCH ()-[r]->() WHERE type(4) = 'ACTED_IN' RETURN r,type(r) /* invalid argument */; +MATCH (a)-->(b)-->(c)<--(d) WHERE id(b) <> id(d) AND id(a) > id(d) AND id(b) < id(c) RETURN a,b,c,d; \ No newline at end of file diff --git a/test/resource/unit_test/function/cypher/function.result b/test/resource/unit_test/function/cypher/function.result new file mode 100644 index 0000000000..a6f842f0ad --- /dev/null +++ b/test/resource/unit_test/function/cypher/function.result @@ -0,0 +1,93 @@ +MATCH (n:Person) RETURN properties(n) LIMIT 2; +[{"properties(n)":{"_LABEL_":"Person","_VID_":12,"birthyear":1970,"name":"Christopher Nolan"}},{"properties(n)":{"_LABEL_":"Person","_VID_":3,"birthyear":1939,"name":"Corin Redgrave"}}] +MATCH p=(n:Person)-[e*..2]->(m) RETURN properties(p) LIMIT 2; +[{"properties(p)":"[{\"_LABEL_\":\"Person\",\"_VID_\":12,\"birthyear\":1970,\"name\":\"Christopher Nolan\"},{\"_LABEL_\":\"BORN_IN\",\"_EID_\":\"12_14_2_0_0\",\"reg_time\":2023-05-01 12:00:00,\"weight\":19.930000},{\"_LABEL_\":\"City\",\"_VID_\":14,\"name\":\"London\"}]"},{"properties(p)":[{"_LABEL_":"Person","_VID_":12,"birthyear":1970,"name":"Christopher Nolan"},{"_EID_":"12_17_3_0_0","_LABEL_":"DIRECTED"},{"_LABEL_":"Film","_VID_":17,"title":"Batman Begins"}]}] +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[relatedTo]-(n) RETURN id(vanessa),type(relatedTo),label(n); +[{"id(vanessa)":2,"label(n)":"Person","type(relatedTo)":"HAS_CHILD"},{"id(vanessa)":2,"label(n)":"City","type(relatedTo)":"BORN_IN"},{"id(vanessa)":2,"label(n)":"Film","type(relatedTo)":"ACTED_IN"},{"id(vanessa)":2,"label(n)":"Person","type(relatedTo)":"HAS_CHILD"},{"id(vanessa)":2,"label(n)":"Person","type(relatedTo)":"HAS_CHILD"}] +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[r]->() RETURN startNode(r),endNode(r); +[{"endNode(r)":5,"startNode(r)":2},{"endNode(r)":14,"startNode(r)":2},{"endNode(r)":20,"startNode(r)":2}] +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[r]->(n) RETURN properties(n); +[{"properties(n)":{"_LABEL_":"Person","_VID_":5,"birthyear":1963,"name":"Natasha Richardson"}},{"properties(n)":{"_LABEL_":"City","_VID_":14,"name":"London"}},{"properties(n)":{"_LABEL_":"Film","_VID_":20,"title":"Camelot"}}] +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[r]->(n) RETURN properties(r); +[{"properties(r)":{"_EID_":"2_5_0_0_0","_LABEL_":"HAS_CHILD"}},{"properties(r)":"{\"_LABEL_\":\"BORN_IN\",\"_EID_\":\"2_14_2_0_0\",\"reg_time\":2023-05-01 10:00:00,\"weight\":20.209999}"},{"properties(r)":{"_EID_":"2_20_5_0_0","_LABEL_":"ACTED_IN","charactername":"Guenevere"}}] +MATCH (a) WHERE a.name = 'Vanessa Redgrave' RETURN label(a), labels(a); +[{"label(a)":"Person","labels(a)":"[Person]"}] +MATCH (a) WHERE a.name = 'Vanessa Redgrave' RETURN keys(a); +[{"keys(a)":"[birthyear,name]"}] +MATCH (a:Person {name:'Vanessa Redgrave'}) RETURN a,-2,9.78,"im a string"; +[{"\"im a string\"":"im a string","-2":-2,"9.78":9.78,"a":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (a:Person {name:'Vanessa Redgrave'}) RETURN a,abs(-2),ceil(0.1),floor(0.9),tointeger(rand()),round(3.141592),sign(-17),sign(0.1); +[{"a":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"abs(-2)":2,"ceil(0.1)":1.0,"floor(0.9)":0.0,"round(3.141592)":3.0,"sign(-17)":-1,"sign(0.1)":1,"tointeger(rand())":0}] +RETURN toInteger(2.0),toInteger(2.3),toInteger('3'); +[{"toInteger('3')":3,"toInteger(2.0)":2,"toInteger(2.3)":2}] +RETURN toBoolean(true),toBoolean('True'); +[{"toBoolean('True')":true,"toBoolean(true)":true}] +RETURN toFloat(2),toFloat(2.3),toFloat('3'),toFloat('2.019'); +[{"toFloat('2.019')":2.019,"toFloat('3')":3.0,"toFloat(2)":2.0,"toFloat(2.3)":2.3}] +RETURN toString(2),toString(2.3),toString(true),toString('haha'); +[{"toString('haha')":"haha","toString(2)":"2","toString(2.3)":"2.300000","toString(true)":"true"}] +RETURN size('hello world!'); +[{"size('hello world!')":12}] +MATCH (n:Person) WHERE size(n.name) > 15 RETURN n.name,size(n.name); +[{"n.name":"Christopher Nolan","size(n.name)":17},{"n.name":"Michael Redgrave","size(n.name)":16},{"n.name":"Natasha Richardson","size(n.name)":18},{"n.name":"Vanessa Redgrave","size(n.name)":16}] +WITH ['one','two','three'] AS coll RETURN size(coll); +[{"size(coll)":3}] +WITH ['one','two','three'] AS coll RETURN head(coll); +[{"head(coll)":"one"}] +WITH ['one','two','three'] AS coll RETURN last(coll); +[{"last(coll)":"three"}] +WITH ['one','two','three'] AS coll UNWIND coll AS x RETURN collect(x); +[{"collect(x)":"[one,two,three]"}] +WITH ['one','two','three'] AS coll UNWIND coll AS x WITH collect(x) AS reColl RETURN head(reColl); +[{"head(reColl)":"one"}] +MATCH (n:Person) RETURN sum(n.birthyear); +[{"sum(n.birthyear)":25219.0}] +MATCH (n:Person) RETURN label(n),sum(n.birthyear); +[{"label(n)":"Person","sum(n.birthyear)":25219.0}] +MATCH (n:Person) RETURN n.name,sum(n.birthyear); +[{"n.name":"Roy Redgrave","sum(n.birthyear)":1873.0},{"n.name":"Richard Harris","sum(n.birthyear)":1930.0},{"n.name":"Rachel Kempson","sum(n.birthyear)":1910.0},{"n.name":"Michael Redgrave","sum(n.birthyear)":1908.0},{"n.name":"Lindsay Lohan","sum(n.birthyear)":1986.0},{"n.name":"Corin Redgrave","sum(n.birthyear)":1939.0},{"n.name":"Vanessa Redgrave","sum(n.birthyear)":1937.0},{"n.name":"Christopher Nolan","sum(n.birthyear)":1970.0},{"n.name":"John Williams","sum(n.birthyear)":1932.0},{"n.name":"Dennis Quaid","sum(n.birthyear)":1954.0},{"n.name":"Jemma Redgrave","sum(n.birthyear)":1965.0},{"n.name":"Natasha Richardson","sum(n.birthyear)":1963.0},{"n.name":"Liam Neeson","sum(n.birthyear)":1952.0}] +MATCH (n:Person) RETURN n.name,label(n),sum(n.birthyear); +[{"label(n)":"Person","n.name":"Vanessa Redgrave","sum(n.birthyear)":1937.0},{"label(n)":"Person","n.name":"Roy Redgrave","sum(n.birthyear)":1873.0},{"label(n)":"Person","n.name":"Corin Redgrave","sum(n.birthyear)":1939.0},{"label(n)":"Person","n.name":"Michael Redgrave","sum(n.birthyear)":1908.0},{"label(n)":"Person","n.name":"Christopher Nolan","sum(n.birthyear)":1970.0},{"label(n)":"Person","n.name":"Rachel Kempson","sum(n.birthyear)":1910.0},{"label(n)":"Person","n.name":"Natasha Richardson","sum(n.birthyear)":1963.0},{"label(n)":"Person","n.name":"Dennis Quaid","sum(n.birthyear)":1954.0},{"label(n)":"Person","n.name":"Richard Harris","sum(n.birthyear)":1930.0},{"label(n)":"Person","n.name":"Jemma Redgrave","sum(n.birthyear)":1965.0},{"label(n)":"Person","n.name":"John Williams","sum(n.birthyear)":1932.0},{"label(n)":"Person","n.name":"Lindsay Lohan","sum(n.birthyear)":1986.0},{"label(n)":"Person","n.name":"Liam Neeson","sum(n.birthyear)":1952.0}] +MATCH (n:Person {name:'Natasha Richardson'})--(m:Person) RETURN m.name,sum(m.birthyear); +[{"m.name":"Vanessa Redgrave","sum(m.birthyear)":1937.0},{"m.name":"Liam Neeson","sum(m.birthyear)":3904.0}] +MATCH (n:Person) RETURN count(n); +[{"count(n)":13}] +MATCH (n:Person) RETURN avg(n.birthyear); +[{"avg(n.birthyear)":1939.923076923077}] +MATCH (n:Person) RETURN max(n.birthyear),min(n.birthyear),sum(n.birthyear); +[{"max(n.birthyear)":1986.0,"min(n.birthyear)":1873.0,"sum(n.birthyear)":25219.0}] +OPTIONAL MATCH (n:City {name:'London'})-[r]->() RETURN count(r); +[{"count(r)":0}] +OPTIONAL MATCH (n:City {name:'London'})-[r]->() RETURN count(*); +[{"count(*)":0}] +MATCH (n:Person) RETURN count(n) AS num_person; +[{"num_person":13}] +match (city:City {name:'New York'}) return id(city) as cityId, coalesce(city.name, city.cname) as cityName; +[{"cityId":13,"cityName":"New York"}] +RETURN coalesce(null); +[{"coalesce(null)":null}] +RETURN coalesce(2021); +[{"coalesce(2021)":2021}] +RETURN coalesce(2021, null); +[{"coalesce(2021, null)":2021}] +RETURN coalesce(null, null); +[{"coalesce(null, null)":null}] +MATCH (n) RETURN coalesce(n.birthyear, n.name); +[{"coalesce(n.birthyear, n.name)":1910},{"coalesce(n.birthyear, n.name)":1908},{"coalesce(n.birthyear, n.name)":1937},{"coalesce(n.birthyear, n.name)":1939},{"coalesce(n.birthyear, n.name)":1952},{"coalesce(n.birthyear, n.name)":1963},{"coalesce(n.birthyear, n.name)":1930},{"coalesce(n.birthyear, n.name)":1954},{"coalesce(n.birthyear, n.name)":1986},{"coalesce(n.birthyear, n.name)":1965},{"coalesce(n.birthyear, n.name)":1873},{"coalesce(n.birthyear, n.name)":1932},{"coalesce(n.birthyear, n.name)":1970},{"coalesce(n.birthyear, n.name)":"New York"},{"coalesce(n.birthyear, n.name)":"London"},{"coalesce(n.birthyear, n.name)":"Houston"},{"coalesce(n.birthyear, n.name)":null},{"coalesce(n.birthyear, n.name)":null},{"coalesce(n.birthyear, n.name)":null},{"coalesce(n.birthyear, n.name)":null},{"coalesce(n.birthyear, n.name)":null}] +#EXPECT +RETURN abs('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function Abs. +RETURN ceil('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function Ceil. +RETURN floor('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function Floor. +RETURN round('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function Round. +RETURN sign('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function Sign. +RETURN toboolean('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function ToBoolean. +RETURN tofloat('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function ToFloat. +RETURN tointeger('haha'); +[CypherException] CypherException: There are errors in the number of arguments or the type of arguments of function ToInteger. diff --git a/test/resource/unit_test/function/cypher/function.test b/test/resource/unit_test/function/cypher/function.test new file mode 100644 index 0000000000..3f63099029 --- /dev/null +++ b/test/resource/unit_test/function/cypher/function.test @@ -0,0 +1,47 @@ +MATCH (n:Person) RETURN properties(n) LIMIT 2; +MATCH p=(n:Person)-[e*..2]->(m) RETURN properties(p) LIMIT 2; +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[relatedTo]-(n) RETURN id(vanessa),type(relatedTo),label(n); +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[r]->() RETURN startNode(r),endNode(r); +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[r]->(n) RETURN properties(n); +MATCH (vanessa:Person {name:'Vanessa Redgrave'})-[r]->(n) RETURN properties(r); +MATCH (a) WHERE a.name = 'Vanessa Redgrave' RETURN label(a), labels(a); +MATCH (a) WHERE a.name = 'Vanessa Redgrave' RETURN keys(a); +MATCH (a:Person {name:'Vanessa Redgrave'}) RETURN a,-2,9.78,"im a string"; +MATCH (a:Person {name:'Vanessa Redgrave'}) RETURN a,abs(-2),ceil(0.1),floor(0.9),tointeger(rand()),round(3.141592),sign(-17),sign(0.1); +RETURN toInteger(2.0),toInteger(2.3),toInteger('3'); +RETURN toBoolean(true),toBoolean('True'); +RETURN toFloat(2),toFloat(2.3),toFloat('3'),toFloat('2.019'); +RETURN toString(2),toString(2.3),toString(true),toString('haha'); +RETURN size('hello world!'); +MATCH (n:Person) WHERE size(n.name) > 15 RETURN n.name,size(n.name); +WITH ['one','two','three'] AS coll RETURN size(coll); +WITH ['one','two','three'] AS coll RETURN head(coll); +WITH ['one','two','three'] AS coll RETURN last(coll); +WITH ['one','two','three'] AS coll UNWIND coll AS x RETURN collect(x); +WITH ['one','two','three'] AS coll UNWIND coll AS x WITH collect(x) AS reColl RETURN head(reColl); +MATCH (n:Person) RETURN sum(n.birthyear); +MATCH (n:Person) RETURN label(n),sum(n.birthyear); +MATCH (n:Person) RETURN n.name,sum(n.birthyear); +MATCH (n:Person) RETURN n.name,label(n),sum(n.birthyear); +MATCH (n:Person {name:'Natasha Richardson'})--(m:Person) RETURN m.name,sum(m.birthyear); +MATCH (n:Person) RETURN count(n); +MATCH (n:Person) RETURN avg(n.birthyear); +MATCH (n:Person) RETURN max(n.birthyear),min(n.birthyear),sum(n.birthyear); +OPTIONAL MATCH (n:City {name:'London'})-[r]->() RETURN count(r); +OPTIONAL MATCH (n:City {name:'London'})-[r]->() RETURN count(*); +MATCH (n:Person) RETURN count(n) AS num_person; +match (city:City {name:'New York'}) return id(city) as cityId, coalesce(city.name, city.cname) as cityName; +RETURN coalesce(null); +RETURN coalesce(2021); +RETURN coalesce(2021, null); +RETURN coalesce(null, null); +MATCH (n) RETURN coalesce(n.birthyear, n.name); +#EXPECT +RETURN abs('haha'); +RETURN ceil('haha'); +RETURN floor('haha'); +RETURN round('haha'); +RETURN sign('haha'); +RETURN toboolean('haha'); +RETURN tofloat('haha'); +RETURN tointeger('haha'); \ No newline at end of file diff --git a/test/resource/unit_test/hint/cypher/hint.result b/test/resource/unit_test/hint/cypher/hint.result new file mode 100644 index 0000000000..26fb934460 --- /dev/null +++ b/test/resource/unit_test/hint/cypher/hint.result @@ -0,0 +1,9 @@ + +MATCH (rachel:Person {name:'Rachel Kempson'})-[]->(family:Person)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(richard:Person {name:'Richard Harris'}) RETURN family.name ; +[{"family.name":"Vanessa Redgrave"}] +MATCH (rachel:Person {name:'Rachel Kempson'})-[]->(family:Person)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(richard:Person {name:'Richard Harris'}) USING JOIN ON film RETURN family.name ; +[{"family.name":"Vanessa Redgrave"}] +MATCH (rachel:Person {name:'Rachel Kempson'})-[]->(family:Person)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(richard:Person {name:'Richard Harris'}) USING JOIN ON family RETURN family.name ; +[{"family.name":"Vanessa Redgrave"}] +MATCH (camelot:Film {title:'Camelot'})<-[:ACTED_IN]-(actor)-[]->(x) USING START ON camelot RETURN x ; +[{"x":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"x":{"identity":14,"label":"City","properties":{"name":"London"}}},{"x":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}}] diff --git a/test/resource/unit_test/hint/cypher/hint.test b/test/resource/unit_test/hint/cypher/hint.test new file mode 100644 index 0000000000..bb0eab1084 --- /dev/null +++ b/test/resource/unit_test/hint/cypher/hint.test @@ -0,0 +1,5 @@ + +MATCH (rachel:Person {name:'Rachel Kempson'})-[]->(family:Person)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(richard:Person {name:'Richard Harris'}) RETURN family.name ; +MATCH (rachel:Person {name:'Rachel Kempson'})-[]->(family:Person)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(richard:Person {name:'Richard Harris'}) USING JOIN ON film RETURN family.name ; +MATCH (rachel:Person {name:'Rachel Kempson'})-[]->(family:Person)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(richard:Person {name:'Richard Harris'}) USING JOIN ON family RETURN family.name ; +MATCH (camelot:Film {title:'Camelot'})<-[:ACTED_IN]-(actor)-[]->(x) USING START ON camelot RETURN x ; \ No newline at end of file diff --git a/test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.result b/test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.result new file mode 100644 index 0000000000..b2902bd453 --- /dev/null +++ b/test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.result @@ -0,0 +1,26 @@ +CALL db.createVertexLabel('TagClass', 'name', 'name', 'STRING', false); +[] +CALL db.createVertexLabel('Tag', 'name', 'name', 'STRING', false); +[] +CALL db.createVertexLabel('Forum', 'name', 'name', 'STRING', false); +[] +CALL db.createVertexLabel('Person', 'id', 'id', 'INT32', false, 'birthday', 'STRING', true); +[] +CALL db.createVertexLabel('Comment', 'id', 'id', 'INT32', false); +[] +CALL db.createVertexLabel('Message', 'id', 'id', 'INT32', false); +[] +CALL db.createEdgeLabel('hasTag', '[]'); +[] +CALL db.createEdgeLabel('hasType', '[]'); +[] +CALL db.createEdgeLabel('knows', '[]'); +[] +CALL db.createEdgeLabel('hasMember', '[]'); +[] +CALL db.createEdgeLabel('hasCreator', '[]'); +[] +CALL db.createEdgeLabel('replyOf', '[]'); +[] + CREATE (tagClass1:TagClass {name: 'MusicalArtist'}), (tagClass2:TagClass {name: 'OfficeHolder'}), (tag1:Tag {name: 'Elvis Presley'}), (tag2:Tag {name: 'Mr. Office'}), (forum1:Forum {name: 'Presley fan club'}), (forum2:Forum {name: 'Long live the closed office'}), (forum1)-[:hasTag]->(tag1)-[:hasType]->(tagClass1), (forum2)-[:hasTag]->(tag2)-[:hasType]->(tagClass2), (person1:Person {id: 1, birthday: '1990-01-01'}), (person2:Person {id: 2, birthday: '1989-01-01'}), (person3:Person {id: 3, birthday: '1989-01-01'}), (person4:Person {id: 4, birthday: '1989-01-01'}), (person1)-[:knows]->(person2), (person2)-[:knows]->(person3), (person3)-[:knows]->(person4), (forum1)-[:hasMember]->(person3)<-[:hasMember]-(forum2), (forum1)-[:hasMember]->(person4)<-[:hasMember]-(forum2), (comment1:Comment {id: 1}), (comment2:Comment {id: 2}), (comment3:Comment {id: 3}), (message1:Message {id: 1}), (message2:Message {id: 2}), (message3:Message {id: 3}), (person1)<-[:hasCreator]-(comment1)-[:replyOf]->(message1)-[:hasCreator]->(person3), (person3)<-[:hasCreator]-(comment2)-[:replyOf]->(message2)-[:hasCreator]->(person1), (person4)<-[:hasCreator]-(comment3)-[:replyOf]->(message3)-[:hasCreator]->(person1) ; +[{"":"created 16 vertices, created 20 edges."}] diff --git a/test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.test b/test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.test new file mode 100644 index 0000000000..4557180aa3 --- /dev/null +++ b/test/resource/unit_test/ldbc_snb/cypher/ldbc_snb.test @@ -0,0 +1,13 @@ +CALL db.createVertexLabel('TagClass', 'name', 'name', 'STRING', false); +CALL db.createVertexLabel('Tag', 'name', 'name', 'STRING', false); +CALL db.createVertexLabel('Forum', 'name', 'name', 'STRING', false); +CALL db.createVertexLabel('Person', 'id', 'id', 'INT32', false, 'birthday', 'STRING', true); +CALL db.createVertexLabel('Comment', 'id', 'id', 'INT32', false); +CALL db.createVertexLabel('Message', 'id', 'id', 'INT32', false); +CALL db.createEdgeLabel('hasTag', '[]'); +CALL db.createEdgeLabel('hasType', '[]'); +CALL db.createEdgeLabel('knows', '[]'); +CALL db.createEdgeLabel('hasMember', '[]'); +CALL db.createEdgeLabel('hasCreator', '[]'); +CALL db.createEdgeLabel('replyOf', '[]'); + CREATE (tagClass1:TagClass {name: 'MusicalArtist'}), (tagClass2:TagClass {name: 'OfficeHolder'}), (tag1:Tag {name: 'Elvis Presley'}), (tag2:Tag {name: 'Mr. Office'}), (forum1:Forum {name: 'Presley fan club'}), (forum2:Forum {name: 'Long live the closed office'}), (forum1)-[:hasTag]->(tag1)-[:hasType]->(tagClass1), (forum2)-[:hasTag]->(tag2)-[:hasType]->(tagClass2), (person1:Person {id: 1, birthday: '1990-01-01'}), (person2:Person {id: 2, birthday: '1989-01-01'}), (person3:Person {id: 3, birthday: '1989-01-01'}), (person4:Person {id: 4, birthday: '1989-01-01'}), (person1)-[:knows]->(person2), (person2)-[:knows]->(person3), (person3)-[:knows]->(person4), (forum1)-[:hasMember]->(person3)<-[:hasMember]-(forum2), (forum1)-[:hasMember]->(person4)<-[:hasMember]-(forum2), (comment1:Comment {id: 1}), (comment2:Comment {id: 2}), (comment3:Comment {id: 3}), (message1:Message {id: 1}), (message2:Message {id: 2}), (message3:Message {id: 3}), (person1)<-[:hasCreator]-(comment1)-[:replyOf]->(message1)-[:hasCreator]->(person3), (person3)<-[:hasCreator]-(comment2)-[:replyOf]->(message2)-[:hasCreator]->(person1), (person4)<-[:hasCreator]-(comment3)-[:replyOf]->(message3)-[:hasCreator]->(person1) ; diff --git a/test/resource/unit_test/list_comprehension/cypher/list_comprehension.result b/test/resource/unit_test/list_comprehension/cypher/list_comprehension.result new file mode 100644 index 0000000000..e19e655a1e --- /dev/null +++ b/test/resource/unit_test/list_comprehension/cypher/list_comprehension.result @@ -0,0 +1,8 @@ +RETURN [x IN range(0,10) | x] AS result; +[{"result":[0,1,2,3,4,5,6,7,8,9,10]}] +RETURN [x IN range(0,10) | x^3] AS result; +[{"result":[0.0,1.0,8.0,27.0,64.0,125.0,216.0,343.0,512.0,729.0,1000.0]}] +WITH [2,4,6] AS y RETURN [x IN y | x] AS result; +[{"result":[2,4,6]}] +WITH [2,4,6] AS y RETURN [x IN range(0, size(y)) | x] AS result; +[{"result":[0,1,2,3]}] diff --git a/test/resource/unit_test/list_comprehension/cypher/list_comprehension.test b/test/resource/unit_test/list_comprehension/cypher/list_comprehension.test new file mode 100644 index 0000000000..c68d7a244b --- /dev/null +++ b/test/resource/unit_test/list_comprehension/cypher/list_comprehension.test @@ -0,0 +1,4 @@ +RETURN [x IN range(0,10) | x] AS result; +RETURN [x IN range(0,10) | x^3] AS result; +WITH [2,4,6] AS y RETURN [x IN y | x] AS result; +WITH [2,4,6] AS y RETURN [x IN range(0, size(y)) | x] AS result; \ No newline at end of file diff --git a/test/resource/unit_test/merge/cypher/merge.result b/test/resource/unit_test/merge/cypher/merge.result new file mode 100644 index 0000000000..3a8fc589de --- /dev/null +++ b/test/resource/unit_test/merge/cypher/merge.result @@ -0,0 +1,77 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'birthyear', 'INT16', true, 'gender', 'INT8', true) ; +[] +CALL db.createVertexLabel('City', 'name', 'name', 'STRING', false, 'area', 'DOUBLE',false, 'population', 'DOUBLE', true) ; +[] +CALL db.createEdgeLabel('Knows', '[]', 'intimacy', 'DOUBLE', true) ; +[] +CALL db.createEdgeLabel('Livein', '[]') ; +[] +CALL db.addIndex('City', 'area', true) ; +[] +CREATE (n:Person {name: 'Liubei', birthyear: 161,gender:1}) ; +[{"":"created 1 vertices, created 0 edges."}] +CREATE (n:Person {name: 'Caocao', birthyear: 155,gender:1}) ; +[{"":"created 1 vertices, created 0 edges."}] +CREATE (n:Person {name: 'Sunquan', birthyear: 182,gender:1}) ; +[{"":"created 1 vertices, created 0 edges."}] +CREATE (n:Person {name: 'Guanyu', birthyear: 160,gender:1}) ; +[{"":"created 1 vertices, created 0 edges."}] +CREATE (n:Person {name: 'Zhangfei', birthyear: 153,gender:1}) ; +[{"":"created 1 vertices, created 0 edges."}] +CREATE (n:City {name: 'Beijing', area:16410.54, population:2154.2}) ; +[{"":"created 1 vertices, created 0 edges."}] +CREATE (n:City {name: 'Shanghai', area:6340.5, population:2423.78}) ; +[{"":"created 1 vertices, created 0 edges."}] + +MERGE (n:Person {name:'Liubei'}) RETURN n.birthyear, n.gender ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'Zhugeliang'}) ON CREATE SET n.gender=1,n.birthyear=181 RETURN n.name ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'Liubei'}) ON MATCH SET n.birthyear=2010 RETURN n.birthyear ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE(n:Person {name:'Liubei'}) ON CREATE SET n.gender=1 ON MATCH SET n.birthyear=2020 RETURN n.name, n.gender,n.birthyear ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE(n:Person {name:'Huatuo'}) ON CREATE SET n.gender=1 ON MATCH SET n.birthyear=2020 RETURN n.name, n.gender,n.birthyear ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE(n:Person {name:'Liubei'}) ON MATCH SET n.gender=0,n.birthyear=2050 RETURN n.name, n.gender,n.birthyear ; +[CypherException] CypherException: cannot match node with given label and properties +MATCH(n:Person {name:'Caocao'}), (m:Person {name:'Sunquan'}) MERGE (n)-[r:Knows{intimacy:0.6}]->(m) RETURN r.intimacy ; +[] +MATCH(n:Person {name:'Caocao'}), (m:Person {name:'Sunquan'}) MERGE (n)-[r:Knows]->(m) RETURN r.intimacy ; +[] +MATCH (n:Person),(m:City) WHERE n.name='Caocao' AND m.name='Beijing' MERGE (n)-[r:Livein]->(m) RETURN r ; +[InputError] Vertex label "Person" does not exist. +MATCH (n:Person {name:'Caocao'}) MERGE (n)-[r:Knows]->(m:Person {name:'Sunquan'})RETURN r ; +[] +MATCH (n:Person),(m:City) WHERE n.birthyear >= 160 AND m.name = 'Beijing' MERGE (n)-[r:Livein]->(m) RETURN r ; +[InputError] Vertex label "Person" does not exist. +MERGE (n:Person {name:'Caocao'})-[r:Knows]->(m:Person {name:'Caogai'})RETURN r ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'Huatuo'}) RETURN n.name ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'Xunyu'}) RETURN n.name ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'Liubei'}) RETURN n.birthyear, n.gender ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (node1: Person {name: 'lisi'}) ON CREATE SET node1.birthyear = 1903 WITH node1 MATCH (node1) WHERE node1.birthyear < 1904 SET node1.birthyear = 1904 RETURN id(node1), node1.name, node1.birthyear ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n: Person {name: 'wangwu'}) ON CREATE SET n.birthyear = 1903 ON CREATE SET n.name = 'wangwu2' WITH n MATCH (n) WHERE n.birthyear < 2002 SET n += {birthyear: 2002, name: 'wangwu2'} RETURN id(n), n.name, n.birthyear ; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (a:Person {name: 'zhangsan'}) SET a.birthyear = 2020 RETURN a.birthyear; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (a:Person {name: 'zhangsan'}) DELETE a; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (a:Person {name: 'zhangsan'}) CREATE (b:Person {name : 'xiaoming'})RETURN b; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) RETURN n,m; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) RETURN n,m; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) CREATE (n)-[r:Knows]->(m) RETURN n, r, m; +[CypherException] CypherException: cannot match node with given label and properties +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) MERGE (n)-[r:Knows]->(m) return n, r, m; +[CypherException] CypherException: cannot match node with given label and properties +MATCH (a:Person {name:'zhangsan'}) SET a.birthyear = 2023 CREATE (b:Person {name:'wangwu'}) RETURN b; +[] +MATCH (a:Person {name:'zhangsan'}) SET a.birthyear = 2023 MERGE (b:Person {name:'wangwu'}) RETURN b; +[] diff --git a/test/resource/unit_test/merge/cypher/merge.test b/test/resource/unit_test/merge/cypher/merge.test new file mode 100644 index 0000000000..0cf1c7af85 --- /dev/null +++ b/test/resource/unit_test/merge/cypher/merge.test @@ -0,0 +1,39 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'birthyear', 'INT16', true, 'gender', 'INT8', true) ; +CALL db.createVertexLabel('City', 'name', 'name', 'STRING', false, 'area', 'DOUBLE',false, 'population', 'DOUBLE', true) ; +CALL db.createEdgeLabel('Knows', '[]', 'intimacy', 'DOUBLE', true) ; +CALL db.createEdgeLabel('Livein', '[]') ; +CALL db.addIndex('City', 'area', true) ; +CREATE (n:Person {name: 'Liubei', birthyear: 161,gender:1}) ; +CREATE (n:Person {name: 'Caocao', birthyear: 155,gender:1}) ; +CREATE (n:Person {name: 'Sunquan', birthyear: 182,gender:1}) ; +CREATE (n:Person {name: 'Guanyu', birthyear: 160,gender:1}) ; +CREATE (n:Person {name: 'Zhangfei', birthyear: 153,gender:1}) ; +CREATE (n:City {name: 'Beijing', area:16410.54, population:2154.2}) ; +CREATE (n:City {name: 'Shanghai', area:6340.5, population:2423.78}) ; + +MERGE (n:Person {name:'Liubei'}) RETURN n.birthyear, n.gender ; +MERGE (n:Person {name:'Zhugeliang'}) ON CREATE SET n.gender=1,n.birthyear=181 RETURN n.name ; +MERGE (n:Person {name:'Liubei'}) ON MATCH SET n.birthyear=2010 RETURN n.birthyear ; +MERGE(n:Person {name:'Liubei'}) ON CREATE SET n.gender=1 ON MATCH SET n.birthyear=2020 RETURN n.name, n.gender,n.birthyear ; +MERGE(n:Person {name:'Huatuo'}) ON CREATE SET n.gender=1 ON MATCH SET n.birthyear=2020 RETURN n.name, n.gender,n.birthyear ; +MERGE(n:Person {name:'Liubei'}) ON MATCH SET n.gender=0,n.birthyear=2050 RETURN n.name, n.gender,n.birthyear ; +MATCH(n:Person {name:'Caocao'}), (m:Person {name:'Sunquan'}) MERGE (n)-[r:Knows{intimacy:0.6}]->(m) RETURN r.intimacy ; +MATCH(n:Person {name:'Caocao'}), (m:Person {name:'Sunquan'}) MERGE (n)-[r:Knows]->(m) RETURN r.intimacy ; +MATCH (n:Person),(m:City) WHERE n.name='Caocao' AND m.name='Beijing' MERGE (n)-[r:Livein]->(m) RETURN r ; +MATCH (n:Person {name:'Caocao'}) MERGE (n)-[r:Knows]->(m:Person {name:'Sunquan'})RETURN r ; +MATCH (n:Person),(m:City) WHERE n.birthyear >= 160 AND m.name = 'Beijing' MERGE (n)-[r:Livein]->(m) RETURN r ; +MERGE (n:Person {name:'Caocao'})-[r:Knows]->(m:Person {name:'Caogai'})RETURN r ; +MERGE (n:Person {name:'Huatuo'}) RETURN n.name ; +MERGE (n:Person {name:'Xunyu'}) RETURN n.name ; +MERGE (n:Person {name:'Liubei'}) RETURN n.birthyear, n.gender ; +MERGE (node1: Person {name: 'lisi'}) ON CREATE SET node1.birthyear = 1903 WITH node1 MATCH (node1) WHERE node1.birthyear < 1904 SET node1.birthyear = 1904 RETURN id(node1), node1.name, node1.birthyear ; +MERGE (n: Person {name: 'wangwu'}) ON CREATE SET n.birthyear = 1903 ON CREATE SET n.name = 'wangwu2' WITH n MATCH (n) WHERE n.birthyear < 2002 SET n += {birthyear: 2002, name: 'wangwu2'} RETURN id(n), n.name, n.birthyear ; +MERGE (a:Person {name: 'zhangsan'}) SET a.birthyear = 2020 RETURN a.birthyear; +MERGE (a:Person {name: 'zhangsan'}) DELETE a; +MERGE (a:Person {name: 'zhangsan'}) CREATE (b:Person {name : 'xiaoming'})RETURN b; +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) RETURN n,m; +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) RETURN n,m; +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) CREATE (n)-[r:Knows]->(m) RETURN n, r, m; +MERGE (n:Person {name:'zhangsan'}) MERGE (m:Person {name:'lisi'}) MERGE (n)-[r:Knows]->(m) return n, r, m; +MATCH (a:Person {name:'zhangsan'}) SET a.birthyear = 2023 CREATE (b:Person {name:'wangwu'}) RETURN b; +MATCH (a:Person {name:'zhangsan'}) SET a.birthyear = 2023 MERGE (b:Person {name:'wangwu'}) RETURN b; \ No newline at end of file diff --git a/test/resource/unit_test/multi_match/cypher/multi_match.result b/test/resource/unit_test/multi_match/cypher/multi_match.result new file mode 100644 index 0000000000..23609ce2e6 --- /dev/null +++ b/test/resource/unit_test/multi_match/cypher/multi_match.result @@ -0,0 +1,9 @@ + +MATCH (p)-[:ACTED_IN]->(x), (p)-[:MARRIED]->(y), (p)-[:HAS_CHILD]->(z) RETURN p,x,y,z; +[{"p":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"x":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"y":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"z":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"p":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"x":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"y":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"z":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}}] +MATCH (x)<-[:ACTED_IN]-(p)-[:MARRIED]->(y), (p)-[:HAS_CHILD]->(z) RETURN p,x,y,z; +[{"p":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"x":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"y":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"z":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"p":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"x":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"y":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"z":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}}] +MATCH (n:Film), (m:City) RETURN n, m; +[{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}}] +MATCH (n1:Person {name: "John Williams"})-[]->(m1:Film), (n2: Person {name: "Michael Redgrave"})-[]->(m2:Film) WHERE m1.title = m2.title RETURN m1, m2; +[{"m1":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"m2":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}}] diff --git a/test/resource/unit_test/multi_match/cypher/multi_match.test b/test/resource/unit_test/multi_match/cypher/multi_match.test new file mode 100644 index 0000000000..9f23765d77 --- /dev/null +++ b/test/resource/unit_test/multi_match/cypher/multi_match.test @@ -0,0 +1,5 @@ + +MATCH (p)-[:ACTED_IN]->(x), (p)-[:MARRIED]->(y), (p)-[:HAS_CHILD]->(z) RETURN p,x,y,z; +MATCH (x)<-[:ACTED_IN]-(p)-[:MARRIED]->(y), (p)-[:HAS_CHILD]->(z) RETURN p,x,y,z; +MATCH (n:Film), (m:City) RETURN n, m; +MATCH (n1:Person {name: "John Williams"})-[]->(m1:Film), (n2: Person {name: "Michael Redgrave"})-[]->(m2:Film) WHERE m1.title = m2.title RETURN m1, m2; \ No newline at end of file diff --git a/test/resource/unit_test/opt/cypher/opt.result b/test/resource/unit_test/opt/cypher/opt.result new file mode 100644 index 0000000000..285faf88cf --- /dev/null +++ b/test/resource/unit_test/opt/cypher/opt.result @@ -0,0 +1,73 @@ +MATCH ()-[r]->() RETURN count(r) /* 28 */; +[{"count(r)":28}] +MATCH (:Person)-[r]->() RETURN count(r) /* 28 */; +[{"count(r)":28}] +MATCH (:Film)-[r]->() RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH ()-[r]->(:Person) RETURN count(r) /* 11 */; +[{"count(r)":11}] +MATCH ()-[r]->(:Film) RETURN count(r) /* 11 */; +[{"count(r)":11}] +MATCH (:Person)-[r]->(:Film) RETURN count(r) /* 11 */; +[{"count(r)":11}] +MATCH (:Person)-[r]->(:NO_LABEL) RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH ()-[r:MARRIED]->() RETURN count(r) /* 4 */; +[{"count(r)":4}] +MATCH ()-[r:NO_LABEL]->() RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH ()-[r:MARRIED|BORN_IN]->() RETURN count(r) /* 10 */; +[{"count(r)":10}] +MATCH ()-[r:MARRIED|BORN_IN|NO_LABEL]->() RETURN count(r) /* 10 */; +[{"count(r)":10}] +MATCH (:Person)-[r:MARRIED|BORN_IN]->() RETURN count(r) /* 10 */; +[{"count(r)":10}] +MATCH (:City)-[r:MARRIED|BORN_IN]->() RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH ()-[r:MARRIED|BORN_IN]->(:Person) RETURN count(r) /* 4 */; +[{"count(r)":4}] +MATCH (:Person)-[r:MARRIED|BORN_IN]->(:City) RETURN count(r) /* 6 */; +[{"count(r)":6}] +MATCH (:Person)-[r:MARRIED|BORN_IN]->(:Film) RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH (:Person)-[r:DIRECTED]->(:Film) RETURN count(r) /* 1 */; +[{"count(r)":1}] +MATCH (:Person)-[r:DIRECTED|ACTED_IN]->(:Film) RETURN count(r) /* 9 */; +[{"count(r)":9}] +MATCH ()-[r]-() RETURN count(r) /* 28 * 2 */; +[{"count(r)":56}] +MATCH (:Person)-[r]-() RETURN count(r) /* 39 */; +[{"count(r)":39}] +MATCH (:Film)-[r]-() RETURN count(r) /* 11 */; +[{"count(r)":11}] +MATCH ()-[r]-(:Person) RETURN count(r) /* 39 */; +[{"count(r)":39}] +MATCH ()-[r]-(:Film) RETURN count(r) /* 11 */; +[{"count(r)":11}] +MATCH (:Person)-[r]-(:Film) RETURN count(r) /* 11 */; +[{"count(r)":11}] +MATCH (:Person)-[r]-(:NO_LABEL) RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH ()-[r:MARRIED]-() RETURN count(r) /* 8 */; +[{"count(r)":8}] +MATCH ()-[r:NO_LABEL]-() RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH ()-[r:MARRIED|BORN_IN]-() RETURN count(r) /* 20 */; +[{"count(r)":20}] +MATCH ()-[r:MARRIED|BORN_IN|NO_LABEL]-() RETURN count(r) /* 20 */; +[{"count(r)":20}] +MATCH (:Person)-[r:MARRIED|BORN_IN]-() RETURN count(r) /* 14 */; +[{"count(r)":14}] +MATCH (:City)-[r:MARRIED|BORN_IN]-() RETURN count(r) /* 6 */; +[{"count(r)":6}] +MATCH ()-[r:MARRIED|BORN_IN]-(:Person) RETURN count(r) /* 14 */; +[{"count(r)":14}] +MATCH (:Person)-[r:MARRIED|BORN_IN]-(:City) RETURN count(r) /* 6 */; +[{"count(r)":6}] +MATCH (:Person)-[r:MARRIED|BORN_IN]-(:Film) RETURN count(r) /* 0 */; +[{"count(r)":0}] +MATCH (:Person)-[r:DIRECTED]-(:Film) RETURN count(r) /* 1 */; +[{"count(r)":1}] +MATCH (:Person)-[r:DIRECTED|ACTED_IN]-(:Film) RETURN count(r) /* 9 */; +[{"count(r)":9}] + diff --git a/test/resource/unit_test/opt/cypher/opt.test b/test/resource/unit_test/opt/cypher/opt.test new file mode 100644 index 0000000000..1ea4e4de73 --- /dev/null +++ b/test/resource/unit_test/opt/cypher/opt.test @@ -0,0 +1,37 @@ +MATCH ()-[r]->() RETURN count(r) /* 28 */; +MATCH (:Person)-[r]->() RETURN count(r) /* 28 */; +MATCH (:Film)-[r]->() RETURN count(r) /* 0 */; +MATCH ()-[r]->(:Person) RETURN count(r) /* 11 */; +MATCH ()-[r]->(:Film) RETURN count(r) /* 11 */; +MATCH (:Person)-[r]->(:Film) RETURN count(r) /* 11 */; +MATCH (:Person)-[r]->(:NO_LABEL) RETURN count(r) /* 0 */; +MATCH ()-[r:MARRIED]->() RETURN count(r) /* 4 */; +MATCH ()-[r:NO_LABEL]->() RETURN count(r) /* 0 */; +MATCH ()-[r:MARRIED|BORN_IN]->() RETURN count(r) /* 10 */; +MATCH ()-[r:MARRIED|BORN_IN|NO_LABEL]->() RETURN count(r) /* 10 */; +MATCH (:Person)-[r:MARRIED|BORN_IN]->() RETURN count(r) /* 10 */; +MATCH (:City)-[r:MARRIED|BORN_IN]->() RETURN count(r) /* 0 */; +MATCH ()-[r:MARRIED|BORN_IN]->(:Person) RETURN count(r) /* 4 */; +MATCH (:Person)-[r:MARRIED|BORN_IN]->(:City) RETURN count(r) /* 6 */; +MATCH (:Person)-[r:MARRIED|BORN_IN]->(:Film) RETURN count(r) /* 0 */; +MATCH (:Person)-[r:DIRECTED]->(:Film) RETURN count(r) /* 1 */; +MATCH (:Person)-[r:DIRECTED|ACTED_IN]->(:Film) RETURN count(r) /* 9 */; +MATCH ()-[r]-() RETURN count(r) /* 28 * 2 */; +MATCH (:Person)-[r]-() RETURN count(r) /* 39 */; +MATCH (:Film)-[r]-() RETURN count(r) /* 11 */; +MATCH ()-[r]-(:Person) RETURN count(r) /* 39 */; +MATCH ()-[r]-(:Film) RETURN count(r) /* 11 */; +MATCH (:Person)-[r]-(:Film) RETURN count(r) /* 11 */; +MATCH (:Person)-[r]-(:NO_LABEL) RETURN count(r) /* 0 */; +MATCH ()-[r:MARRIED]-() RETURN count(r) /* 8 */; +MATCH ()-[r:NO_LABEL]-() RETURN count(r) /* 0 */; +MATCH ()-[r:MARRIED|BORN_IN]-() RETURN count(r) /* 20 */; +MATCH ()-[r:MARRIED|BORN_IN|NO_LABEL]-() RETURN count(r) /* 20 */; +MATCH (:Person)-[r:MARRIED|BORN_IN]-() RETURN count(r) /* 14 */; +MATCH (:City)-[r:MARRIED|BORN_IN]-() RETURN count(r) /* 6 */; +MATCH ()-[r:MARRIED|BORN_IN]-(:Person) RETURN count(r) /* 14 */; +MATCH (:Person)-[r:MARRIED|BORN_IN]-(:City) RETURN count(r) /* 6 */; +MATCH (:Person)-[r:MARRIED|BORN_IN]-(:Film) RETURN count(r) /* 0 */; +MATCH (:Person)-[r:DIRECTED]-(:Film) RETURN count(r) /* 1 */; +MATCH (:Person)-[r:DIRECTED|ACTED_IN]-(:Film) RETURN count(r) /* 9 */; + diff --git a/test/resource/unit_test/optional_match/cypher/optional_match.result b/test/resource/unit_test/optional_match/cypher/optional_match.result new file mode 100644 index 0000000000..f47a59dd28 --- /dev/null +++ b/test/resource/unit_test/optional_match/cypher/optional_match.result @@ -0,0 +1,19 @@ + +MATCH (n:Person {name:'NoOne'}) RETURN n; +[] +OPTIONAL MATCH (n:Person {name:'NoOne'}) RETURN n; +[{"n":"__null__"}] +OPTIONAL MATCH (n:City {name:'London'})-[r]->(m) RETURN n.name, r, m; +[{"m":"__null__","n.name":null,"r":{"dst":0,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":14,"temporal_id":0}}] +OPTIONAL MATCH (n:City {name:'London'})-[r]-(m) RETURN n.name, r, m; +[{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n.name":"London","r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n.name":"London","r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 11:00:00","weight":20.18},"src":5,"temporal_id":0}},{"m":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"n.name":"London","r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 12:00:00","weight":19.93},"src":12,"temporal_id":0}}] +MATCH (n:City {name:'London'}) WITH n.name AS city_name OPTIONAL MATCH (n:Person {name:'NoOne'}) RETURN n.name, city_name; +[{"city_name":"London","n.name":null}] +MATCH (n:City) WITH n MATCH (n)-->(m) RETURN n,m; +[] +MATCH (n:City) WITH n OPTIONAL MATCH (n)-->(m) RETURN n,m; +[{"m":"__null__","n":{"identity":15,"label":"City","properties":{"name":"Houston"}}},{"m":"__null__","n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":"__null__","n":{"identity":13,"label":"City","properties":{"name":"New York"}}}] + +# MATCH (n:City {name:'London'}) OPTIONAL MATCH (n)-[r]->(m) RETURN n.name, r, m ; +# MATCH (n:City {name:'London'}) OPTIONAL MATCH (m:NoLabel) RETURN n.name, m ; +# MATCH (n:Person {name:'Vanessa Redgrave'}) OPTIONAL MATCH (n)-[:ACTED_IN]->(m)-[:NoType]->(l) RETURN n, m, l; diff --git a/test/resource/unit_test/optional_match/cypher/optional_match.test b/test/resource/unit_test/optional_match/cypher/optional_match.test new file mode 100644 index 0000000000..579443673a --- /dev/null +++ b/test/resource/unit_test/optional_match/cypher/optional_match.test @@ -0,0 +1,12 @@ + +MATCH (n:Person {name:'NoOne'}) RETURN n; +OPTIONAL MATCH (n:Person {name:'NoOne'}) RETURN n; +OPTIONAL MATCH (n:City {name:'London'})-[r]->(m) RETURN n.name, r, m; +OPTIONAL MATCH (n:City {name:'London'})-[r]-(m) RETURN n.name, r, m; +MATCH (n:City {name:'London'}) WITH n.name AS city_name OPTIONAL MATCH (n:Person {name:'NoOne'}) RETURN n.name, city_name; +MATCH (n:City) WITH n MATCH (n)-->(m) RETURN n,m; +MATCH (n:City) WITH n OPTIONAL MATCH (n)-->(m) RETURN n,m; + +# MATCH (n:City {name:'London'}) OPTIONAL MATCH (n)-[r]->(m) RETURN n.name, r, m ; +# MATCH (n:City {name:'London'}) OPTIONAL MATCH (m:NoLabel) RETURN n.name, m ; +# MATCH (n:Person {name:'Vanessa Redgrave'}) OPTIONAL MATCH (n)-[:ACTED_IN]->(m)-[:NoType]->(l) RETURN n, m, l; \ No newline at end of file diff --git a/test/resource/unit_test/orderby/cypher/orderby.result b/test/resource/unit_test/orderby/cypher/orderby.result new file mode 100644 index 0000000000..712476855c --- /dev/null +++ b/test/resource/unit_test/orderby/cypher/orderby.result @@ -0,0 +1,35 @@ +#MATCH (a:Person {name:'Lindsay Lohan'}), (b:Film {title:'The Parent Trap'}) CREATE (a)-[r:DIRECTED]->(b); +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(v2) as cnt; +[{"cnt":3,"v1.title":"The Parent Trap"},{"cnt":1,"v1.title":"Harry Potter and the Sorcerer's Stone"},{"cnt":1,"v1.title":"Goodbye, Mr. Chips"},{"cnt":2,"v1.title":"Batman Begins"},{"cnt":2,"v1.title":"Camelot"}] +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt; +[{"cnt":3,"v1.title":"The Parent Trap"},{"cnt":1,"v1.title":"Harry Potter and the Sorcerer's Stone"},{"cnt":1,"v1.title":"Goodbye, Mr. Chips"},{"cnt":2,"v1.title":"Batman Begins"},{"cnt":2,"v1.title":"Camelot"}] +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt; +[{"cnt":1,"v1.title":"Harry Potter and the Sorcerer's Stone"},{"cnt":1,"v1.title":"Goodbye, Mr. Chips"},{"cnt":2,"v1.title":"Batman Begins"},{"cnt":2,"v1.title":"Camelot"},{"cnt":3,"v1.title":"The Parent Trap"}] +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt desc; +[{"cnt":3,"v1.title":"The Parent Trap"},{"cnt":2,"v1.title":"Batman Begins"},{"cnt":2,"v1.title":"Camelot"},{"cnt":1,"v1.title":"Harry Potter and the Sorcerer's Stone"},{"cnt":1,"v1.title":"Goodbye, Mr. Chips"}] +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt desc,v1.title; +[{"cnt":3,"v1.title":"The Parent Trap"},{"cnt":2,"v1.title":"Batman Begins"},{"cnt":2,"v1.title":"Camelot"},{"cnt":1,"v1.title":"Goodbye, Mr. Chips"},{"cnt":1,"v1.title":"Harry Potter and the Sorcerer's Stone"}] +match (v1:Film) return distinct v1.title order by v1.title; +[{"v1.title":"Batman Begins"},{"v1.title":"Camelot"},{"v1.title":"Goodbye, Mr. Chips"},{"v1.title":"Harry Potter and the Sorcerer's Stone"},{"v1.title":"The Parent Trap"}] +match (v1:Film) return distinct v1.title order by v1.title limit 3 /* Batman, Camelot, Goodbye */; +[{"v1.title":"Batman Begins"},{"v1.title":"Camelot"},{"v1.title":"Goodbye, Mr. Chips"}] +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt desc limit 3 /* NOTE: unstable heap sort */; +[{"cnt":3,"v1.title":"The Parent Trap"},{"cnt":2,"v1.title":"Camelot"},{"cnt":2,"v1.title":"Batman Begins"}] +match (:Person {name:'Vanessa Redgrave'})<-[:HAS_CHILD]-(p)-[:ACTED_IN*0..]->(m) return p.name,m order by p.name; +[{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"p.name":"Michael Redgrave"},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"p.name":"Michael Redgrave"},{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"p.name":"Rachel Kempson"}] +MATCH (n) RETURN n,n.name AS name ORDER BY name; +[{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"name":null},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"name":null},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"name":null},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"name":null},{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"name":null},{"n":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"name":"Christopher Nolan"},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"name":"Corin Redgrave"},{"n":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"name":"Dennis Quaid"},{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"name":"Houston"},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"name":"Jemma Redgrave"},{"n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"name":"John Williams"},{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"name":"Liam Neeson"},{"n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"name":"Lindsay Lohan"},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"name":"London"},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"name":"Michael Redgrave"},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"name":"Natasha Richardson"},{"n":{"identity":13,"label":"City","properties":{"name":"New York"}},"name":"New York"},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"name":"Rachel Kempson"},{"n":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"name":"Richard Harris"},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"name":"Roy Redgrave"},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"name":"Vanessa Redgrave"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN m.name; +[{"m.name":"Liam Neeson"},{"m.name":"Liam Neeson"},{"m.name":"Natasha Richardson"},{"m.name":"Christopher Nolan"},{"m.name":"Richard Harris"},{"m.name":"Corin Redgrave"},{"m.name":"Michael Redgrave"},{"m.name":"Michael Redgrave"},{"m.name":"Corin Redgrave"},{"m.name":"Rachel Kempson"},{"m.name":"Roy Redgrave"},{"m.name":"Rachel Kempson"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name; +[{"m.name":"Liam Neeson"},{"m.name":"Natasha Richardson"},{"m.name":"Christopher Nolan"},{"m.name":"Richard Harris"},{"m.name":"Corin Redgrave"},{"m.name":"Michael Redgrave"},{"m.name":"Rachel Kempson"},{"m.name":"Roy Redgrave"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name; +[{"m.name":"Christopher Nolan"},{"m.name":"Corin Redgrave"},{"m.name":"Liam Neeson"},{"m.name":"Michael Redgrave"},{"m.name":"Natasha Richardson"},{"m.name":"Rachel Kempson"},{"m.name":"Richard Harris"},{"m.name":"Roy Redgrave"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name LIMIT 5; +[{"m.name":"Christopher Nolan"},{"m.name":"Corin Redgrave"},{"m.name":"Liam Neeson"},{"m.name":"Michael Redgrave"},{"m.name":"Natasha Richardson"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name SKIP 2; +[{"m.name":"Liam Neeson"},{"m.name":"Michael Redgrave"},{"m.name":"Natasha Richardson"},{"m.name":"Rachel Kempson"},{"m.name":"Richard Harris"},{"m.name":"Roy Redgrave"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name SKIP 2 LIMIT 3; +[{"m.name":"Liam Neeson"},{"m.name":"Michael Redgrave"},{"m.name":"Natasha Richardson"}] +MATCH (v1:Film)<-[r:ACTED_IN|DIRECTED]-(v2:Person) RETURN v1.title AS title, r ORDER BY title LIMIT 5; +[{"r":{"dst":17,"forward":false,"identity":0,"label":"DIRECTED","label_id":3,"src":12,"temporal_id":0},"title":"Batman Begins"},{"r":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0},"title":"Batman Begins"},{"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"King Arthur"},"src":6,"temporal_id":0},"title":"Camelot"},{"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},"title":"Camelot"},{"r":{"dst":16,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},"title":"Goodbye, Mr. Chips"}] diff --git a/test/resource/unit_test/orderby/cypher/orderby.test b/test/resource/unit_test/orderby/cypher/orderby.test new file mode 100644 index 0000000000..b2a3ae6aab --- /dev/null +++ b/test/resource/unit_test/orderby/cypher/orderby.test @@ -0,0 +1,18 @@ +#MATCH (a:Person {name:'Lindsay Lohan'}), (b:Film {title:'The Parent Trap'}) CREATE (a)-[r:DIRECTED]->(b); +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(v2) as cnt; +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt; +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt; +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt desc; +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt desc,v1.title; +match (v1:Film) return distinct v1.title order by v1.title; +match (v1:Film) return distinct v1.title order by v1.title limit 3 /* Batman, Camelot, Goodbye */; +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by cnt desc limit 3 /* NOTE: unstable heap sort */; +match (:Person {name:'Vanessa Redgrave'})<-[:HAS_CHILD]-(p)-[:ACTED_IN*0..]->(m) return p.name,m order by p.name; +MATCH (n) RETURN n,n.name AS name ORDER BY name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN m.name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name LIMIT 5; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name SKIP 2; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN DISTINCT m.name ORDER BY m.name SKIP 2 LIMIT 3; +MATCH (v1:Film)<-[r:ACTED_IN|DIRECTED]-(v2:Person) RETURN v1.title AS title, r ORDER BY title LIMIT 5; \ No newline at end of file diff --git a/test/resource/unit_test/parameter/cypher/paratemer.test b/test/resource/unit_test/parameter/cypher/paratemer.test new file mode 100644 index 0000000000..d8376762ed --- /dev/null +++ b/test/resource/unit_test/parameter/cypher/paratemer.test @@ -0,0 +1,2 @@ +MATCH (n:Person) WHERE n.name = $name RETURN n; +MATCH (n:Person {name:$name}) RETURN n; \ No newline at end of file diff --git a/test/resource/unit_test/procedure/cypher/procedure.result b/test/resource/unit_test/procedure/cypher/procedure.result new file mode 100644 index 0000000000..ab57e8be9f --- /dev/null +++ b/test/resource/unit_test/procedure/cypher/procedure.result @@ -0,0 +1,206 @@ +-- loadProcedure scan_graph ../../test/test_procedures/scan_graph.cpp read_only=true +-- loadProcedure standard ../../test/test_procedures/standard_result.cpp read_only=true +-- loadProcedure custom_shortestpath ../../test/test_procedures/v2_path_process.cpp read_only=true +-- loadProcedure custom_pagerank ../../test/test_procedures/v2_pagerank.cpp read_only=true +-- loadProcedure peek_some_node_salt ../../test/test_procedures/peek_some_node_salt.cpp read_only=true +-- loadProcedure custom_path_process ../../test/test_procedures/v2_path_process.cpp read_only=true +-- loadProcedure custom_algo ../../test/test_procedures/v2_algo.cpp read_only=true + +CALL db.createVertexLabel('Director', 'name', 'name', STRING, false, 'age', INT16, true); +[] +CALL db.createVertexLabel('P2', 'flag1', 'flag1', BOOL, false, 'flag2', Bool, true); +[] +CALL db.createEdgeLabel('LIKE', '[]'); +[] +CALL db.addIndex('Person', 'birthyear', false); +[] +CAll db.subgraph([1,2,3]); +[{"subgraph":{"nodes":[{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}],"relationships":[{"dst":2,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},{"dst":3,"forward":true,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0}]}}] +CALL db.vertexLabels; +[{"label":"Person"},{"label":"City"},{"label":"Film"},{"label":"Director"},{"label":"P2"}] +CALL db.edgeLabels; +[{"label":"HAS_CHILD"},{"label":"MARRIED"},{"label":"BORN_IN"},{"label":"DIRECTED"},{"label":"WROTE_MUSIC_FOR"},{"label":"ACTED_IN"},{"label":"LIKE"}] +CALL db.indexes; +[{"field":"birthyear","label":"Person","label_type":"vertex","pair_unique":false,"unique":false},{"field":"name","label":"Person","label_type":"vertex","pair_unique":false,"unique":true},{"field":"name","label":"City","label_type":"vertex","pair_unique":false,"unique":true},{"field":"title","label":"Film","label_type":"vertex","pair_unique":false,"unique":true},{"field":"name","label":"Director","label_type":"vertex","pair_unique":false,"unique":true},{"field":"flag1","label":"P2","label_type":"vertex","pair_unique":false,"unique":true}] +CALL dbms.procedures; +[{"name":"db.subgraph","read_only":true,"signature":"db.subgraph(vids::LIST) :: (subgraph::STRING)"},{"name":"db.vertexLabels","read_only":true,"signature":"db.vertexLabels() :: (label::STRING)"},{"name":"db.edgeLabels","read_only":true,"signature":"db.edgeLabels() :: (label::STRING)"},{"name":"db.indexes","read_only":true,"signature":"db.indexes() :: (label::STRING,field::STRING,label_type::STRING,unique::BOOLEAN,pair_unique::BOOLEAN)"},{"name":"db.listLabelIndexes","read_only":true,"signature":"db.listLabelIndexes(label_name::STRING,label_type::LIST) :: (label::STRING,field::STRING,unique::BOOLEAN,pair_unique::BOOLEAN)"},{"name":"db.propertyKeys","read_only":true,"signature":"db.propertyKeys() :: (propertyKey::STRING)"},{"name":"db.warmup","read_only":true,"signature":"db.warmup() :: (time_used::STRING)"},{"name":"db.createVertexLabelByJson","read_only":false,"signature":"db.createVertexLabelByJson(json_data::STRING) :: (::NUL)"},{"name":"db.createEdgeLabelByJson","read_only":false,"signature":"db.createEdgeLabelByJson(json_data::STRING) :: (::NUL)"},{"name":"db.createVertexLabel","read_only":false,"signature":"db.createVertexLabel(label_name::STRING,field_specs::LIST) :: (::NUL)"},{"name":"db.createLabel","read_only":false,"signature":"db.createLabel(label_type::STRING,label_name::STRING,extra::STRING,field_specs::LIST) :: ()"},{"name":"db.getLabelSchema","read_only":true,"signature":"db.getLabelSchema(label_type::STRING,label_name::STRING) :: (name::STRING,type::STRING,optional::BOOLEAN)"},{"name":"db.getVertexSchema","read_only":true,"signature":"db.getVertexSchema(label::STRING) :: (schema::MAP)"},{"name":"db.getEdgeSchema","read_only":true,"signature":"db.getEdgeSchema(label::STRING) :: (schema::MAP)"},{"name":"db.deleteLabel","read_only":false,"signature":"db.deleteLabel(label_type::STRING,label_name::STRING) :: (::NUL)"},{"name":"db.alterLabelDelFields","read_only":false,"signature":"db.alterLabelDelFields(label_type::STRING,label_name::STRING,del_fields::LIST) :: (record_affected::INTEGER)"},{"name":"db.alterLabelAddFields","read_only":false,"signature":"db.alterLabelAddFields(label_type::STRING,label_name::STRING,add_field_spec_values::LIST) :: (record_affected::INTEGER)"},{"name":"db.upsertVertex","read_only":false,"signature":"db.upsertVertex(label_name::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.upsertVertexByJson","read_only":false,"signature":"db.upsertVertexByJson(label_name::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.upsertEdge","read_only":false,"signature":"db.upsertEdge(label_name::STRING,start_spec::STRING,end_spec::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.upsertEdgeByJson","read_only":false,"signature":"db.upsertEdgeByJson(label_name::STRING,start_spec::STRING,end_spec::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.alterLabelModFields","read_only":false,"signature":"db.alterLabelModFields(label_type::STRING,label_name::STRING,mod_field_specs::LIST) :: (record_affected::INTEGER)"},{"name":"db.createEdgeLabel","read_only":false,"signature":"db.createEdgeLabel(type_name::STRING,field_specs::LIST) :: (::NUL)"},{"name":"db.addIndex","read_only":false,"signature":"db.addIndex(label_name::STRING,field_name::STRING,unique::BOOLEAN) :: (::NUL)"},{"name":"db.addEdgeIndex","read_only":false,"signature":"db.addEdgeIndex(label_name::STRING,field_name::STRING,unique::BOOLEAN,) :: (::NUL)"},{"name":"db.addFullTextIndex","read_only":false,"signature":"db.addFullTextIndex(is_vertex::BOOLEAN,label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.deleteFullTextIndex","read_only":false,"signature":"db.deleteFullTextIndex(is_vertex::BOOLEAN,label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.rebuildFullTextIndex","read_only":false,"signature":"db.rebuildFullTextIndex(vertex_labels::STRING,edge_labels::STRING) :: (::NUL)"},{"name":"db.fullTextIndexes","read_only":true,"signature":"db.fullTextIndexes() :: (is_vertex::BOOLEAN,label::STRING,field::STRING)"},{"name":"db.addEdgeConstraints","read_only":false,"signature":"db.addEdgeConstraints(label_name::STRING,constraints::STRING) :: (::NUL)"},{"name":"db.clearEdgeConstraints","read_only":false,"signature":"db.clearEdgeConstraints(label_name::STRING) :: (::NUL)"},{"name":"dbms.procedures","read_only":true,"signature":"dbms.procedures() :: (name::STRING,signature::STRING,read_only::BOOLEAN)"},{"name":"dbms.meta.countDetail","read_only":true,"signature":"dbms.meta.countDetail() :: (is_vertex::BOOLEAN,label::STRING,count::INTEGER)"},{"name":"dbms.meta.count","read_only":true,"signature":"dbms.meta.count() :: (type::STRING,number::INTEGER)"},{"name":"dbms.meta.refreshCount","read_only":false,"signature":"dbms.meta.refreshCount() :: (::NUL)"},{"name":"dbms.security.changePassword","read_only":false,"signature":"dbms.security.changePassword(current_password::STRING,new_password::STRING) :: (::NUL)"},{"name":"dbms.security.changeUserPassword","read_only":false,"signature":"dbms.security.changeUserPassword(user_name::STRING,new_password::STRING) :: (::NUL)"},{"name":"dbms.security.createUser","read_only":false,"signature":"dbms.security.createUser(user_name::STRING,password::STRING) :: (::NUL)"},{"name":"dbms.security.deleteUser","read_only":false,"signature":"dbms.security.deleteUser(user_name::STRING) :: (::NUL)"},{"name":"dbms.security.setUserMemoryLimit","read_only":false,"signature":"dbms.security.setUserMemoryLimit(user_name::STRING,MemoryLimit::INTEGER) :: (::NUL)"},{"name":"dbms.security.listUsers","read_only":true,"signature":"dbms.security.listUsers() :: (user_name::STRING,user_info::MAP)"},{"name":"dbms.security.showCurrentUser","read_only":true,"signature":"dbms.security.showCurrentUser() :: (current_user::STRING)"},{"name":"dbms.security.listAllowedHosts","read_only":true,"signature":"dbms.security.listAllowedHosts() :: (host::STRING)"},{"name":"dbms.security.deleteAllowedHosts","read_only":false,"signature":"dbms.security.deleteAllowedHosts(hosts::LIST) :: (record_affected::INTEGER)"},{"name":"dbms.security.addAllowedHosts","read_only":false,"signature":"dbms.security.addAllowedHosts(hosts::LIST) :: (num_added::INTEGER)"},{"name":"dbms.graph.createGraph","read_only":false,"signature":"dbms.graph.createGraph(graph_name::STRING,description::STRING,max_size_GB::INTEGER) :: (::NUL)"},{"name":"dbms.graph.deleteGraph","read_only":false,"signature":"dbms.graph.deleteGraph(graph_name::STRING) :: (::NUL)"},{"name":"dbms.graph.modGraph","read_only":false,"signature":"dbms.graph.modGraph(graph_name::STRING,config::MAP) :: (::NUL)"},{"name":"dbms.graph.listGraphs","read_only":true,"signature":"dbms.graph.listGraphs() :: (graph_name::STRING,configuration::MAP)"},{"name":"dbms.graph.listUserGraphs","read_only":true,"signature":"dbms.graph.listUserGraphs(user_name::STRING) :: (graph_name::STRING,configuration::MAP)"},{"name":"dbms.graph.getGraphInfo","read_only":true,"signature":"dbms.graph.getGraphInfo() :: (graph_name::STRING,configuration::MAP)"},{"name":"dbms.graph.getGraphSchema","read_only":true,"signature":"dbms.graph.getGraphSchema() :: (schema::STRING)"},{"name":"dbms.system.info","read_only":true,"signature":"dbms.system.info() :: (name::STRING,value::ANY)"},{"name":"dbms.config.list","read_only":true,"signature":"dbms.config.list() :: (name::STRING,value::ANY)"},{"name":"dbms.config.update","read_only":false,"signature":"dbms.config.update(updates::MAP) :: (::NUL)"},{"name":"dbms.takeSnapshot","read_only":false,"signature":"dbms.takeSnapshot() :: (path::STRING)"},{"name":"dbms.listBackupFiles","read_only":true,"signature":"dbms.listBackupFiles() :: (file::STRING)"},{"name":"algo.shortestPath","read_only":true,"signature":"algo.shortestPath(startNode::NODE,endNode::NODE,config::MAP) :: (nodeCount::INTEGER,totalCost::FLOAT,path::STRING)"},{"name":"algo.allShortestPaths","read_only":true,"signature":"algo.allShortestPaths(startNode::NODE,endNode::NODE,config::MAP) :: (nodeIds::LIST,relationshipIds::LIST,cost::LIST)"},{"name":"algo.native.extract","read_only":true,"signature":"algo.native.extract(id::ANY,config::MAP) :: (value::ANY)"},{"name":"algo.pagerank","read_only":true,"signature":"algo.pagerank(num_iterations::INTEGER) :: (node::NODE,pr::FLOAT)"},{"name":"algo.jaccard","read_only":true,"signature":"algo.jaccard(lhs::ANY,) :: (similarity::FLOAT)"},{"name":"spatial.distance","read_only":true,"signature":"spatial.distance(Spatial1::STRING,Spatial2::STRING) :: (distance::DOUBLE)"},{"name":"dbms.security.listRoles","read_only":true,"signature":"dbms.security.listRoles() :: (role_name::STRING,role_info::MAP)"},{"name":"dbms.security.createRole","read_only":false,"signature":"dbms.security.createRole(role_name::STRING,desc::STRING) :: (::NUL)"},{"name":"dbms.security.deleteRole","read_only":false,"signature":"dbms.security.deleteRole(role_name::STRING) :: (::NUL)"},{"name":"dbms.security.getUserInfo","read_only":true,"signature":"dbms.security.getUserInfo(user::STRING) :: (user_info::MAP)"},{"name":"dbms.security.getUserMemoryUsage","read_only":true,"signature":"dbms.security.getUserMemoryUsage(user::STRING) :: (memory_usage::INTEGER)"},{"name":"dbms.security.getUserPermissions","read_only":true,"signature":"dbms.security.getUserPermissions(user::STRING) :: (user_info::MAP)"},{"name":"dbms.security.getRoleInfo","read_only":true,"signature":"dbms.security.getRoleInfo(role::STRING) :: (role_info::MAP)"},{"name":"dbms.security.disableRole","read_only":false,"signature":"dbms.security.disableRole(role::STRING,disable::BOOLEAN) :: (::NUL)"},{"name":"dbms.security.modRoleDesc","read_only":false,"signature":"dbms.security.modRoleDesc(role::STRING,description::STRING) :: (::NUL)"},{"name":"dbms.security.rebuildRoleAccessLevel","read_only":false,"signature":"dbms.security.rebuildRoleAccessLevel(role::STRING,access_level::MAP) :: (::NUL)"},{"name":"dbms.security.modRoleAccessLevel","read_only":false,"signature":"dbms.security.modRoleAccessLevel(role::STRING,access_level::MAP) :: (::NUL)"},{"name":"dbms.security.modRoleFieldAccessLevel","read_only":false,"signature":"dbms.security.modRoleFieldAccessLevel(role::STRING,) :: (::NUL)"},{"name":"dbms.security.disableUser","read_only":false,"signature":"dbms.security.disableUser(user::STRING,disable::BOOLEAN) :: (::NUL)"},{"name":"dbms.security.setCurrentDesc","read_only":false,"signature":"dbms.security.setCurrentDesc(description::STRING) :: (::NUL)"},{"name":"dbms.security.setUserDesc","read_only":false,"signature":"dbms.security.setUserDesc(user::STRING,description::STRING) :: (::NUL)"},{"name":"dbms.security.deleteUserRoles","read_only":false,"signature":"dbms.security.deleteUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"name":"dbms.security.rebuildUserRoles","read_only":false,"signature":"dbms.security.rebuildUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"name":"dbms.security.addUserRoles","read_only":false,"signature":"dbms.security.addUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"name":"db.plugin.loadPlugin","read_only":false,"signature":"db.plugin.loadPlugin(plugin_type::STRING,plugin_name::STRING,plugin_content::ANY,code_type::STRING,plugin_description::STRING,read_only::BOOLEAN,version::STRING) :: (::NUL)"},{"name":"db.plugin.deletePlugin","read_only":false,"signature":"db.plugin.deletePlugin(plugin_type::STRING,plugin_name::STRING) :: (::NUL)"},{"name":"db.plugin.getPluginInfo","read_only":true,"signature":"db.plugin.getPluginInfo(plugin_type::STRING,plugin_name::STRING) :: (plugin_description::MAP)"},{"name":"db.plugin.listPlugin","read_only":false,"signature":"db.plugin.listPlugin(plugin_type::STRING,plugin_version::STRING) :: (plugin_description::MAP)"},{"name":"db.plugin.listUserPlugins","read_only":true,"signature":"db.plugin.listUserPlugins() :: (graph::STRING,plugins::MAP)"},{"name":"db.plugin.callPlugin","read_only":false,"signature":"db.plugin.callPlugin(plugin_type::STRING,plugin_name::STRING,param::STRING,timeout::DOUBLE,in_process::BOOLEAN) :: (result::STRING)"},{"name":"db.importor.dataImportor","read_only":false,"signature":"db.importor.dataImportor(description::STRING,content::STRING,continue_on_error::BOOLEAN,thread_nums::INTEGER,delimiter::STRING) :: (::NUL)"},{"name":"db.importor.fullImportor","read_only":false,"signature":"db.importor.fullImportor(conf::MAP) :: (result::STRING)"},{"name":"db.importor.fullFileImportor","read_only":false,"signature":"db.importor.fullFileImportor(graph_name::STRING,path::STRING) :: (::NUL)"},{"name":"db.importor.schemaImportor","read_only":false,"signature":"db.importor.schemaImportor(description::STRING) :: (::NUL)"},{"name":"db.deleteIndex","read_only":false,"signature":"db.deleteIndex(label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.deleteEdgeIndex","read_only":false,"signature":"db.deleteEdgeIndex(label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.flushDB","read_only":false,"signature":"db.flushDB() :: (::NUL)"},{"name":"db.dropDB","read_only":false,"signature":"db.dropDB() :: (::NUL)"},{"name":"dbms.task.listTasks","read_only":true,"signature":"dbms.task.listTasks() :: (tasks_info::MAP)"},{"name":"dbms.task.terminateTask","read_only":false,"signature":"dbms.task.terminateTask(task_id::STRING) :: (::NUL)"},{"name":"db.monitor.tuGraphInfo","read_only":false,"signature":"db.monitor.tuGraphInfo() :: (request::STRING)"},{"name":"db.monitor.serverInfo","read_only":false,"signature":"db.monitor.serverInfo() :: (cpu::STRING,memory::STRING,disk_rate::STRING,disk_storage::STRING)"},{"name":"dbms.ha.clusterInfo","read_only":true,"signature":"dbms.ha.clusterInfo() :: (cluster_info::LIST,is_master::BOOLEAN)"}] +CALL dbms.procedures YIELD signature; +[{"signature":"db.subgraph(vids::LIST) :: (subgraph::STRING)"},{"signature":"db.vertexLabels() :: (label::STRING)"},{"signature":"db.edgeLabels() :: (label::STRING)"},{"signature":"db.indexes() :: (label::STRING,field::STRING,label_type::STRING,unique::BOOLEAN,pair_unique::BOOLEAN)"},{"signature":"db.listLabelIndexes(label_name::STRING,label_type::LIST) :: (label::STRING,field::STRING,unique::BOOLEAN,pair_unique::BOOLEAN)"},{"signature":"db.propertyKeys() :: (propertyKey::STRING)"},{"signature":"db.warmup() :: (time_used::STRING)"},{"signature":"db.createVertexLabelByJson(json_data::STRING) :: (::NUL)"},{"signature":"db.createEdgeLabelByJson(json_data::STRING) :: (::NUL)"},{"signature":"db.createVertexLabel(label_name::STRING,field_specs::LIST) :: (::NUL)"},{"signature":"db.createLabel(label_type::STRING,label_name::STRING,extra::STRING,field_specs::LIST) :: ()"},{"signature":"db.getLabelSchema(label_type::STRING,label_name::STRING) :: (name::STRING,type::STRING,optional::BOOLEAN)"},{"signature":"db.getVertexSchema(label::STRING) :: (schema::MAP)"},{"signature":"db.getEdgeSchema(label::STRING) :: (schema::MAP)"},{"signature":"db.deleteLabel(label_type::STRING,label_name::STRING) :: (::NUL)"},{"signature":"db.alterLabelDelFields(label_type::STRING,label_name::STRING,del_fields::LIST) :: (record_affected::INTEGER)"},{"signature":"db.alterLabelAddFields(label_type::STRING,label_name::STRING,add_field_spec_values::LIST) :: (record_affected::INTEGER)"},{"signature":"db.upsertVertex(label_name::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"signature":"db.upsertVertexByJson(label_name::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"signature":"db.upsertEdge(label_name::STRING,start_spec::STRING,end_spec::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"signature":"db.upsertEdgeByJson(label_name::STRING,start_spec::STRING,end_spec::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"signature":"db.alterLabelModFields(label_type::STRING,label_name::STRING,mod_field_specs::LIST) :: (record_affected::INTEGER)"},{"signature":"db.createEdgeLabel(type_name::STRING,field_specs::LIST) :: (::NUL)"},{"signature":"db.addIndex(label_name::STRING,field_name::STRING,unique::BOOLEAN) :: (::NUL)"},{"signature":"db.addEdgeIndex(label_name::STRING,field_name::STRING,unique::BOOLEAN,) :: (::NUL)"},{"signature":"db.addFullTextIndex(is_vertex::BOOLEAN,label_name::STRING,field_name::STRING) :: (::NUL)"},{"signature":"db.deleteFullTextIndex(is_vertex::BOOLEAN,label_name::STRING,field_name::STRING) :: (::NUL)"},{"signature":"db.rebuildFullTextIndex(vertex_labels::STRING,edge_labels::STRING) :: (::NUL)"},{"signature":"db.fullTextIndexes() :: (is_vertex::BOOLEAN,label::STRING,field::STRING)"},{"signature":"db.addEdgeConstraints(label_name::STRING,constraints::STRING) :: (::NUL)"},{"signature":"db.clearEdgeConstraints(label_name::STRING) :: (::NUL)"},{"signature":"dbms.procedures() :: (name::STRING,signature::STRING,read_only::BOOLEAN)"},{"signature":"dbms.meta.countDetail() :: (is_vertex::BOOLEAN,label::STRING,count::INTEGER)"},{"signature":"dbms.meta.count() :: (type::STRING,number::INTEGER)"},{"signature":"dbms.meta.refreshCount() :: (::NUL)"},{"signature":"dbms.security.changePassword(current_password::STRING,new_password::STRING) :: (::NUL)"},{"signature":"dbms.security.changeUserPassword(user_name::STRING,new_password::STRING) :: (::NUL)"},{"signature":"dbms.security.createUser(user_name::STRING,password::STRING) :: (::NUL)"},{"signature":"dbms.security.deleteUser(user_name::STRING) :: (::NUL)"},{"signature":"dbms.security.setUserMemoryLimit(user_name::STRING,MemoryLimit::INTEGER) :: (::NUL)"},{"signature":"dbms.security.listUsers() :: (user_name::STRING,user_info::MAP)"},{"signature":"dbms.security.showCurrentUser() :: (current_user::STRING)"},{"signature":"dbms.security.listAllowedHosts() :: (host::STRING)"},{"signature":"dbms.security.deleteAllowedHosts(hosts::LIST) :: (record_affected::INTEGER)"},{"signature":"dbms.security.addAllowedHosts(hosts::LIST) :: (num_added::INTEGER)"},{"signature":"dbms.graph.createGraph(graph_name::STRING,description::STRING,max_size_GB::INTEGER) :: (::NUL)"},{"signature":"dbms.graph.deleteGraph(graph_name::STRING) :: (::NUL)"},{"signature":"dbms.graph.modGraph(graph_name::STRING,config::MAP) :: (::NUL)"},{"signature":"dbms.graph.listGraphs() :: (graph_name::STRING,configuration::MAP)"},{"signature":"dbms.graph.listUserGraphs(user_name::STRING) :: (graph_name::STRING,configuration::MAP)"},{"signature":"dbms.graph.getGraphInfo() :: (graph_name::STRING,configuration::MAP)"},{"signature":"dbms.graph.getGraphSchema() :: (schema::STRING)"},{"signature":"dbms.system.info() :: (name::STRING,value::ANY)"},{"signature":"dbms.config.list() :: (name::STRING,value::ANY)"},{"signature":"dbms.config.update(updates::MAP) :: (::NUL)"},{"signature":"dbms.takeSnapshot() :: (path::STRING)"},{"signature":"dbms.listBackupFiles() :: (file::STRING)"},{"signature":"algo.shortestPath(startNode::NODE,endNode::NODE,config::MAP) :: (nodeCount::INTEGER,totalCost::FLOAT,path::STRING)"},{"signature":"algo.allShortestPaths(startNode::NODE,endNode::NODE,config::MAP) :: (nodeIds::LIST,relationshipIds::LIST,cost::LIST)"},{"signature":"algo.native.extract(id::ANY,config::MAP) :: (value::ANY)"},{"signature":"algo.pagerank(num_iterations::INTEGER) :: (node::NODE,pr::FLOAT)"},{"signature":"algo.jaccard(lhs::ANY,) :: (similarity::FLOAT)"},{"signature":"spatial.distance(Spatial1::STRING,Spatial2::STRING) :: (distance::DOUBLE)"},{"signature":"dbms.security.listRoles() :: (role_name::STRING,role_info::MAP)"},{"signature":"dbms.security.createRole(role_name::STRING,desc::STRING) :: (::NUL)"},{"signature":"dbms.security.deleteRole(role_name::STRING) :: (::NUL)"},{"signature":"dbms.security.getUserInfo(user::STRING) :: (user_info::MAP)"},{"signature":"dbms.security.getUserMemoryUsage(user::STRING) :: (memory_usage::INTEGER)"},{"signature":"dbms.security.getUserPermissions(user::STRING) :: (user_info::MAP)"},{"signature":"dbms.security.getRoleInfo(role::STRING) :: (role_info::MAP)"},{"signature":"dbms.security.disableRole(role::STRING,disable::BOOLEAN) :: (::NUL)"},{"signature":"dbms.security.modRoleDesc(role::STRING,description::STRING) :: (::NUL)"},{"signature":"dbms.security.rebuildRoleAccessLevel(role::STRING,access_level::MAP) :: (::NUL)"},{"signature":"dbms.security.modRoleAccessLevel(role::STRING,access_level::MAP) :: (::NUL)"},{"signature":"dbms.security.modRoleFieldAccessLevel(role::STRING,) :: (::NUL)"},{"signature":"dbms.security.disableUser(user::STRING,disable::BOOLEAN) :: (::NUL)"},{"signature":"dbms.security.setCurrentDesc(description::STRING) :: (::NUL)"},{"signature":"dbms.security.setUserDesc(user::STRING,description::STRING) :: (::NUL)"},{"signature":"dbms.security.deleteUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"signature":"dbms.security.rebuildUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"signature":"dbms.security.addUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"signature":"db.plugin.loadPlugin(plugin_type::STRING,plugin_name::STRING,plugin_content::ANY,code_type::STRING,plugin_description::STRING,read_only::BOOLEAN,version::STRING) :: (::NUL)"},{"signature":"db.plugin.deletePlugin(plugin_type::STRING,plugin_name::STRING) :: (::NUL)"},{"signature":"db.plugin.getPluginInfo(plugin_type::STRING,plugin_name::STRING) :: (plugin_description::MAP)"},{"signature":"db.plugin.listPlugin(plugin_type::STRING,plugin_version::STRING) :: (plugin_description::MAP)"},{"signature":"db.plugin.listUserPlugins() :: (graph::STRING,plugins::MAP)"},{"signature":"db.plugin.callPlugin(plugin_type::STRING,plugin_name::STRING,param::STRING,timeout::DOUBLE,in_process::BOOLEAN) :: (result::STRING)"},{"signature":"db.importor.dataImportor(description::STRING,content::STRING,continue_on_error::BOOLEAN,thread_nums::INTEGER,delimiter::STRING) :: (::NUL)"},{"signature":"db.importor.fullImportor(conf::MAP) :: (result::STRING)"},{"signature":"db.importor.fullFileImportor(graph_name::STRING,path::STRING) :: (::NUL)"},{"signature":"db.importor.schemaImportor(description::STRING) :: (::NUL)"},{"signature":"db.deleteIndex(label_name::STRING,field_name::STRING) :: (::NUL)"},{"signature":"db.deleteEdgeIndex(label_name::STRING,field_name::STRING) :: (::NUL)"},{"signature":"db.flushDB() :: (::NUL)"},{"signature":"db.dropDB() :: (::NUL)"},{"signature":"dbms.task.listTasks() :: (tasks_info::MAP)"},{"signature":"dbms.task.terminateTask(task_id::STRING) :: (::NUL)"},{"signature":"db.monitor.tuGraphInfo() :: (request::STRING)"},{"signature":"db.monitor.serverInfo() :: (cpu::STRING,memory::STRING,disk_rate::STRING,disk_storage::STRING)"},{"signature":"dbms.ha.clusterInfo() :: (cluster_info::LIST,is_master::BOOLEAN)"}] +CALL dbms.procedures YIELD signature, name; +[{"name":"db.subgraph","signature":"db.subgraph(vids::LIST) :: (subgraph::STRING)"},{"name":"db.vertexLabels","signature":"db.vertexLabels() :: (label::STRING)"},{"name":"db.edgeLabels","signature":"db.edgeLabels() :: (label::STRING)"},{"name":"db.indexes","signature":"db.indexes() :: (label::STRING,field::STRING,label_type::STRING,unique::BOOLEAN,pair_unique::BOOLEAN)"},{"name":"db.listLabelIndexes","signature":"db.listLabelIndexes(label_name::STRING,label_type::LIST) :: (label::STRING,field::STRING,unique::BOOLEAN,pair_unique::BOOLEAN)"},{"name":"db.propertyKeys","signature":"db.propertyKeys() :: (propertyKey::STRING)"},{"name":"db.warmup","signature":"db.warmup() :: (time_used::STRING)"},{"name":"db.createVertexLabelByJson","signature":"db.createVertexLabelByJson(json_data::STRING) :: (::NUL)"},{"name":"db.createEdgeLabelByJson","signature":"db.createEdgeLabelByJson(json_data::STRING) :: (::NUL)"},{"name":"db.createVertexLabel","signature":"db.createVertexLabel(label_name::STRING,field_specs::LIST) :: (::NUL)"},{"name":"db.createLabel","signature":"db.createLabel(label_type::STRING,label_name::STRING,extra::STRING,field_specs::LIST) :: ()"},{"name":"db.getLabelSchema","signature":"db.getLabelSchema(label_type::STRING,label_name::STRING) :: (name::STRING,type::STRING,optional::BOOLEAN)"},{"name":"db.getVertexSchema","signature":"db.getVertexSchema(label::STRING) :: (schema::MAP)"},{"name":"db.getEdgeSchema","signature":"db.getEdgeSchema(label::STRING) :: (schema::MAP)"},{"name":"db.deleteLabel","signature":"db.deleteLabel(label_type::STRING,label_name::STRING) :: (::NUL)"},{"name":"db.alterLabelDelFields","signature":"db.alterLabelDelFields(label_type::STRING,label_name::STRING,del_fields::LIST) :: (record_affected::INTEGER)"},{"name":"db.alterLabelAddFields","signature":"db.alterLabelAddFields(label_type::STRING,label_name::STRING,add_field_spec_values::LIST) :: (record_affected::INTEGER)"},{"name":"db.upsertVertex","signature":"db.upsertVertex(label_name::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.upsertVertexByJson","signature":"db.upsertVertexByJson(label_name::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.upsertEdge","signature":"db.upsertEdge(label_name::STRING,start_spec::STRING,end_spec::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.upsertEdgeByJson","signature":"db.upsertEdgeByJson(label_name::STRING,start_spec::STRING,end_spec::STRING,list_data::STRING) :: (total::INTEGER,data_error::INTEGER,index_conflict::INTEGER,insert::INTEGER,update::INTEGER)"},{"name":"db.alterLabelModFields","signature":"db.alterLabelModFields(label_type::STRING,label_name::STRING,mod_field_specs::LIST) :: (record_affected::INTEGER)"},{"name":"db.createEdgeLabel","signature":"db.createEdgeLabel(type_name::STRING,field_specs::LIST) :: (::NUL)"},{"name":"db.addIndex","signature":"db.addIndex(label_name::STRING,field_name::STRING,unique::BOOLEAN) :: (::NUL)"},{"name":"db.addEdgeIndex","signature":"db.addEdgeIndex(label_name::STRING,field_name::STRING,unique::BOOLEAN,) :: (::NUL)"},{"name":"db.addFullTextIndex","signature":"db.addFullTextIndex(is_vertex::BOOLEAN,label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.deleteFullTextIndex","signature":"db.deleteFullTextIndex(is_vertex::BOOLEAN,label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.rebuildFullTextIndex","signature":"db.rebuildFullTextIndex(vertex_labels::STRING,edge_labels::STRING) :: (::NUL)"},{"name":"db.fullTextIndexes","signature":"db.fullTextIndexes() :: (is_vertex::BOOLEAN,label::STRING,field::STRING)"},{"name":"db.addEdgeConstraints","signature":"db.addEdgeConstraints(label_name::STRING,constraints::STRING) :: (::NUL)"},{"name":"db.clearEdgeConstraints","signature":"db.clearEdgeConstraints(label_name::STRING) :: (::NUL)"},{"name":"dbms.procedures","signature":"dbms.procedures() :: (name::STRING,signature::STRING,read_only::BOOLEAN)"},{"name":"dbms.meta.countDetail","signature":"dbms.meta.countDetail() :: (is_vertex::BOOLEAN,label::STRING,count::INTEGER)"},{"name":"dbms.meta.count","signature":"dbms.meta.count() :: (type::STRING,number::INTEGER)"},{"name":"dbms.meta.refreshCount","signature":"dbms.meta.refreshCount() :: (::NUL)"},{"name":"dbms.security.changePassword","signature":"dbms.security.changePassword(current_password::STRING,new_password::STRING) :: (::NUL)"},{"name":"dbms.security.changeUserPassword","signature":"dbms.security.changeUserPassword(user_name::STRING,new_password::STRING) :: (::NUL)"},{"name":"dbms.security.createUser","signature":"dbms.security.createUser(user_name::STRING,password::STRING) :: (::NUL)"},{"name":"dbms.security.deleteUser","signature":"dbms.security.deleteUser(user_name::STRING) :: (::NUL)"},{"name":"dbms.security.setUserMemoryLimit","signature":"dbms.security.setUserMemoryLimit(user_name::STRING,MemoryLimit::INTEGER) :: (::NUL)"},{"name":"dbms.security.listUsers","signature":"dbms.security.listUsers() :: (user_name::STRING,user_info::MAP)"},{"name":"dbms.security.showCurrentUser","signature":"dbms.security.showCurrentUser() :: (current_user::STRING)"},{"name":"dbms.security.listAllowedHosts","signature":"dbms.security.listAllowedHosts() :: (host::STRING)"},{"name":"dbms.security.deleteAllowedHosts","signature":"dbms.security.deleteAllowedHosts(hosts::LIST) :: (record_affected::INTEGER)"},{"name":"dbms.security.addAllowedHosts","signature":"dbms.security.addAllowedHosts(hosts::LIST) :: (num_added::INTEGER)"},{"name":"dbms.graph.createGraph","signature":"dbms.graph.createGraph(graph_name::STRING,description::STRING,max_size_GB::INTEGER) :: (::NUL)"},{"name":"dbms.graph.deleteGraph","signature":"dbms.graph.deleteGraph(graph_name::STRING) :: (::NUL)"},{"name":"dbms.graph.modGraph","signature":"dbms.graph.modGraph(graph_name::STRING,config::MAP) :: (::NUL)"},{"name":"dbms.graph.listGraphs","signature":"dbms.graph.listGraphs() :: (graph_name::STRING,configuration::MAP)"},{"name":"dbms.graph.listUserGraphs","signature":"dbms.graph.listUserGraphs(user_name::STRING) :: (graph_name::STRING,configuration::MAP)"},{"name":"dbms.graph.getGraphInfo","signature":"dbms.graph.getGraphInfo() :: (graph_name::STRING,configuration::MAP)"},{"name":"dbms.graph.getGraphSchema","signature":"dbms.graph.getGraphSchema() :: (schema::STRING)"},{"name":"dbms.system.info","signature":"dbms.system.info() :: (name::STRING,value::ANY)"},{"name":"dbms.config.list","signature":"dbms.config.list() :: (name::STRING,value::ANY)"},{"name":"dbms.config.update","signature":"dbms.config.update(updates::MAP) :: (::NUL)"},{"name":"dbms.takeSnapshot","signature":"dbms.takeSnapshot() :: (path::STRING)"},{"name":"dbms.listBackupFiles","signature":"dbms.listBackupFiles() :: (file::STRING)"},{"name":"algo.shortestPath","signature":"algo.shortestPath(startNode::NODE,endNode::NODE,config::MAP) :: (nodeCount::INTEGER,totalCost::FLOAT,path::STRING)"},{"name":"algo.allShortestPaths","signature":"algo.allShortestPaths(startNode::NODE,endNode::NODE,config::MAP) :: (nodeIds::LIST,relationshipIds::LIST,cost::LIST)"},{"name":"algo.native.extract","signature":"algo.native.extract(id::ANY,config::MAP) :: (value::ANY)"},{"name":"algo.pagerank","signature":"algo.pagerank(num_iterations::INTEGER) :: (node::NODE,pr::FLOAT)"},{"name":"algo.jaccard","signature":"algo.jaccard(lhs::ANY,) :: (similarity::FLOAT)"},{"name":"spatial.distance","signature":"spatial.distance(Spatial1::STRING,Spatial2::STRING) :: (distance::DOUBLE)"},{"name":"dbms.security.listRoles","signature":"dbms.security.listRoles() :: (role_name::STRING,role_info::MAP)"},{"name":"dbms.security.createRole","signature":"dbms.security.createRole(role_name::STRING,desc::STRING) :: (::NUL)"},{"name":"dbms.security.deleteRole","signature":"dbms.security.deleteRole(role_name::STRING) :: (::NUL)"},{"name":"dbms.security.getUserInfo","signature":"dbms.security.getUserInfo(user::STRING) :: (user_info::MAP)"},{"name":"dbms.security.getUserMemoryUsage","signature":"dbms.security.getUserMemoryUsage(user::STRING) :: (memory_usage::INTEGER)"},{"name":"dbms.security.getUserPermissions","signature":"dbms.security.getUserPermissions(user::STRING) :: (user_info::MAP)"},{"name":"dbms.security.getRoleInfo","signature":"dbms.security.getRoleInfo(role::STRING) :: (role_info::MAP)"},{"name":"dbms.security.disableRole","signature":"dbms.security.disableRole(role::STRING,disable::BOOLEAN) :: (::NUL)"},{"name":"dbms.security.modRoleDesc","signature":"dbms.security.modRoleDesc(role::STRING,description::STRING) :: (::NUL)"},{"name":"dbms.security.rebuildRoleAccessLevel","signature":"dbms.security.rebuildRoleAccessLevel(role::STRING,access_level::MAP) :: (::NUL)"},{"name":"dbms.security.modRoleAccessLevel","signature":"dbms.security.modRoleAccessLevel(role::STRING,access_level::MAP) :: (::NUL)"},{"name":"dbms.security.modRoleFieldAccessLevel","signature":"dbms.security.modRoleFieldAccessLevel(role::STRING,) :: (::NUL)"},{"name":"dbms.security.disableUser","signature":"dbms.security.disableUser(user::STRING,disable::BOOLEAN) :: (::NUL)"},{"name":"dbms.security.setCurrentDesc","signature":"dbms.security.setCurrentDesc(description::STRING) :: (::NUL)"},{"name":"dbms.security.setUserDesc","signature":"dbms.security.setUserDesc(user::STRING,description::STRING) :: (::NUL)"},{"name":"dbms.security.deleteUserRoles","signature":"dbms.security.deleteUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"name":"dbms.security.rebuildUserRoles","signature":"dbms.security.rebuildUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"name":"dbms.security.addUserRoles","signature":"dbms.security.addUserRoles(user::STRING,roles::LIST) :: (::NUL)"},{"name":"db.plugin.loadPlugin","signature":"db.plugin.loadPlugin(plugin_type::STRING,plugin_name::STRING,plugin_content::ANY,code_type::STRING,plugin_description::STRING,read_only::BOOLEAN,version::STRING) :: (::NUL)"},{"name":"db.plugin.deletePlugin","signature":"db.plugin.deletePlugin(plugin_type::STRING,plugin_name::STRING) :: (::NUL)"},{"name":"db.plugin.getPluginInfo","signature":"db.plugin.getPluginInfo(plugin_type::STRING,plugin_name::STRING) :: (plugin_description::MAP)"},{"name":"db.plugin.listPlugin","signature":"db.plugin.listPlugin(plugin_type::STRING,plugin_version::STRING) :: (plugin_description::MAP)"},{"name":"db.plugin.listUserPlugins","signature":"db.plugin.listUserPlugins() :: (graph::STRING,plugins::MAP)"},{"name":"db.plugin.callPlugin","signature":"db.plugin.callPlugin(plugin_type::STRING,plugin_name::STRING,param::STRING,timeout::DOUBLE,in_process::BOOLEAN) :: (result::STRING)"},{"name":"db.importor.dataImportor","signature":"db.importor.dataImportor(description::STRING,content::STRING,continue_on_error::BOOLEAN,thread_nums::INTEGER,delimiter::STRING) :: (::NUL)"},{"name":"db.importor.fullImportor","signature":"db.importor.fullImportor(conf::MAP) :: (result::STRING)"},{"name":"db.importor.fullFileImportor","signature":"db.importor.fullFileImportor(graph_name::STRING,path::STRING) :: (::NUL)"},{"name":"db.importor.schemaImportor","signature":"db.importor.schemaImportor(description::STRING) :: (::NUL)"},{"name":"db.deleteIndex","signature":"db.deleteIndex(label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.deleteEdgeIndex","signature":"db.deleteEdgeIndex(label_name::STRING,field_name::STRING) :: (::NUL)"},{"name":"db.flushDB","signature":"db.flushDB() :: (::NUL)"},{"name":"db.dropDB","signature":"db.dropDB() :: (::NUL)"},{"name":"dbms.task.listTasks","signature":"dbms.task.listTasks() :: (tasks_info::MAP)"},{"name":"dbms.task.terminateTask","signature":"dbms.task.terminateTask(task_id::STRING) :: (::NUL)"},{"name":"db.monitor.tuGraphInfo","signature":"db.monitor.tuGraphInfo() :: (request::STRING)"},{"name":"db.monitor.serverInfo","signature":"db.monitor.serverInfo() :: (cpu::STRING,memory::STRING,disk_rate::STRING,disk_storage::STRING)"},{"name":"dbms.ha.clusterInfo","signature":"dbms.ha.clusterInfo() :: (cluster_info::LIST,is_master::BOOLEAN)"}] +CALL dbms.graph.createGraph('demo1'); +[] +CALL dbms.graph.listGraphs(); +[{"configuration":{"description":"","max_size_GB":4096},"graph_name":"default"},{"configuration":{"description":"","max_size_GB":4096},"graph_name":"demo1"}] +CALL dbms.graph.deleteGraph('demo1'); +[] +CALL dbms.graph.listGraphs(); +[{"configuration":{"description":"","max_size_GB":4096},"graph_name":"default"}] +CALL dbms.security.showCurrentUser(); +[{"current_user":"admin"}] +CALL dbms.security.changePassword('73@TuGraph','000'); +[] +CALL dbms.security.changePassword('000','73@TuGraph'); +[] +CALL dbms.security.createUser('guest1','123'); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"},{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest1"]},"user_name":"guest1"}] +CALL dbms.security.changeUserPassword('guest1','abc'); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"},{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest1"]},"user_name":"guest1"}] +CALL dbms.security.deleteUser('guest1'); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"}] +CALL dbms.graph.createGraph('demo2'); +[] +CALL dbms.security.createUser('guest2','123'); +[] +CALL dbms.system.info(); +[{"name":"lgraph_version","value":"4.2.0"},{"name":"up_time","value":0.0},{"name":"git_branch","value":"\"cypher_join_ast\""},{"name":"git_commit","value":"\"df86ed6\""},{"name":"web_commit","value":"\"8253763\""},{"name":"cpp_id","value":"\"GNU\""},{"name":"cpp_version","value":"\"8.2.0\""},{"name":"python_version","value":"\"3.6.8\""}] +CALL dbms.config.list(); +[{"name":"bind_host","value":"0.0.0.0"},{"name":"disable_auth","value":false},{"name":"durable","value":false},{"name":"enable_audit_log","value":false},{"name":"enable_backup_log","value":false},{"name":"enable_fulltext_index","value":false},{"name":"enable_ha","value":false},{"name":"enable_ip_check","value":false},{"name":"enable_rpc","value":false},{"name":"enable_ssl","value":false},{"name":"optimistic_txn","value":false},{"name":"port","value":7071},{"name":"subprocess_max_idle_seconds","value":600},{"name":"thread_limit","value":0},{"name":"verbose","value":1}] +CALL dbms.security.listAllowedHosts(); +[] +CALL dbms.security.addAllowedHosts('192.168.1.2', '192.168.1.3'); +[{"num_added":2}] +CALL dbms.security.deleteAllowedHosts('192.168.1.2'); +[{"record_affected":1}] +CALL dbms.security.createUser('guest1','123'); +[] +CALL dbms.security.getUserInfo('guest1'); +[{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest1"]}}] +CALL dbms.security.listRoles(); +[{"role_info":{"description":"Administrators. Builtin role, cannot be modified.","disabled":false,"field_permissions":null,"permissions":{"default":"FULL","demo2":"FULL"}},"role_name":"admin"},{"role_info":{"description":"primary role for user guest1","disabled":false,"field_permissions":null,"permissions":null},"role_name":"guest1"},{"role_info":{"description":"primary role for user guest2","disabled":false,"field_permissions":null,"permissions":null},"role_name":"guest2"}] +CALL dbms.security.createRole('test_role', 'test desc'); +[] +CALL dbms.security.getRoleInfo('test_role'); +[{"role_info":{"description":"test desc","disabled":false,"field_permissions":null,"permissions":null}}] +CALL dbms.security.modRoleDesc('test_role', 'modify test desc'); +[] +CALL dbms.security.disableRole('test_role', true); +[] +CALL dbms.security.getRoleInfo('test_role'); +[{"role_info":{"description":"modify test desc","disabled":true,"field_permissions":null,"permissions":null}}] +CALL dbms.security.disableRole('test_role', false); +[] +CALL dbms.graph.createGraph('tgraph1', 'test graph tgraph1', 1); +[] +CALL dbms.graph.createGraph('tgraph2', 'test graph tgraph2', 2); +[] +CALL dbms.graph.createGraph('tgraph3', 'test graph tgraph3', 3); +[] +CALL dbms.security.rebuildRoleAccessLevel('test_role', {tgraph1: 'READ', tgraph2: 'WRITE', tgraph3: 'FULL'}); +[] +CALL dbms.security.getRoleInfo('test_role'); +[{"role_info":{"description":"modify test desc","disabled":false,"field_permissions":null,"permissions":{"tgraph1":"READ","tgraph2":"WRITE","tgraph3":"FULL"}}}] +CALL dbms.security.modRoleAccessLevel('test_role', {tgraph1: 'NONE', tgraph2: 'NONE', tgraph3: 'WRITE'}); +[] +CALL dbms.security.getRoleInfo('test_role'); +[{"role_info":{"description":"modify test desc","disabled":false,"field_permissions":null,"permissions":{"tgraph3":"WRITE"}}}] +CALL dbms.security.disableUser('guest1', true); +[] +CALL dbms.security.setUserDesc('guest1', 'modify guest1 desc'); +[] +CALL dbms.security.setCurrentDesc('modify root desc'); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"modify root desc","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"},{"user_info":{"auth_method":"@builtin_auth@","description":"modify guest1 desc","disabled":true,"memory_limit":2199023255552,"roles":["guest1"]},"user_name":"guest1"},{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest2"]},"user_name":"guest2"}] +CALL dbms.security.createRole('test_role1', 'test desc'); +[] +CALL dbms.security.createRole('test_role2', 'test desc'); +[] +CALL dbms.security.createRole('test_role3', 'test desc'); +[] +CALL dbms.security.listRoles(); +[{"role_info":{"description":"Administrators. Builtin role, cannot be modified.","disabled":false,"field_permissions":null,"permissions":{"default":"FULL","demo2":"FULL","tgraph1":"FULL","tgraph2":"FULL","tgraph3":"FULL"}},"role_name":"admin"},{"role_info":{"description":"primary role for user guest1","disabled":false,"field_permissions":null,"permissions":null},"role_name":"guest1"},{"role_info":{"description":"primary role for user guest2","disabled":false,"field_permissions":null,"permissions":null},"role_name":"guest2"},{"role_info":{"description":"modify test desc","disabled":false,"field_permissions":null,"permissions":{"tgraph3":"WRITE"}},"role_name":"test_role"},{"role_info":{"description":"test desc","disabled":false,"field_permissions":null,"permissions":null},"role_name":"test_role1"},{"role_info":{"description":"test desc","disabled":false,"field_permissions":null,"permissions":null},"role_name":"test_role2"},{"role_info":{"description":"test desc","disabled":false,"field_permissions":null,"permissions":null},"role_name":"test_role3"}] +CALL dbms.security.rebuildUserRoles('guest1', ['test_role1', 'test_role2', 'test_role3']); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"modify root desc","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"},{"user_info":{"auth_method":"@builtin_auth@","description":"modify guest1 desc","disabled":true,"memory_limit":2199023255552,"roles":["test_role1","test_role2","guest1","test_role3"]},"user_name":"guest1"},{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest2"]},"user_name":"guest2"}] +CALL dbms.security.deleteUserRoles('guest1', ['test_role2', 'test_role3']); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"modify root desc","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"},{"user_info":{"auth_method":"@builtin_auth@","description":"modify guest1 desc","disabled":true,"memory_limit":2199023255552,"roles":["guest1","test_role1"]},"user_name":"guest1"},{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest2"]},"user_name":"guest2"}] +CALL dbms.security.addUserRoles('guest1', ['test_role2', 'test_role3']); +[] +CALL dbms.security.listUsers(); +[{"user_info":{"auth_method":"@builtin_auth@","description":"modify root desc","disabled":false,"memory_limit":2199023255552,"roles":["admin"]},"user_name":"admin"},{"user_info":{"auth_method":"@builtin_auth@","description":"modify guest1 desc","disabled":true,"memory_limit":2199023255552,"roles":["test_role3","guest1","test_role2"]},"user_name":"guest1"},{"user_info":{"auth_method":"@builtin_auth@","description":"","disabled":false,"memory_limit":2199023255552,"roles":["guest2"]},"user_name":"guest2"}] +CALL dbms.security.deleteRole('test_role'); +[] +CALL dbms.security.deleteUser('guest1'); +[] +CALL db.plugin.listPlugin('CPP', 'any'); +[{"plugin_description":{"code_type":"cpp","description":"custom_algo","name":"custom_algo","read_only":true,"signature":{"input":null,"output":[{"name":"res","type":"STRING"}]},"version":"v1"}},{"plugin_description":{"code_type":"cpp","description":"custom_pagerank","name":"custom_pagerank","read_only":true,"signature":{"input":[{"name":"num_iteration","type":"INTEGER"}],"output":[{"name":"node","type":"NODE"},{"name":"weight","type":"DOUBLE"}]},"version":"v1"}},{"plugin_description":{"code_type":"cpp","description":"custom_path_process","name":"custom_path_process","read_only":true,"signature":{"input":[{"name":"nodeIds","type":"LIST"}],"output":[{"name":"idSum","type":"INTEGER"}]},"version":"v1"}},{"plugin_description":{"code_type":"cpp","description":"custom_shortestpath","name":"custom_shortestpath","read_only":true,"signature":{"input":[{"name":"nodeIds","type":"LIST"}],"output":[{"name":"idSum","type":"INTEGER"}]},"version":"v1"}},{"plugin_description":{"code_type":"cpp","description":"peek_some_node_salt","name":"peek_some_node_salt","read_only":true,"signature":{"input":[{"name":"limit","type":"INTEGER"}],"output":[{"name":"node","type":"NODE"},{"name":"salt","type":"FLOAT"}]},"version":"v1"}},{"plugin_description":{"code_type":"cpp","description":"scan_graph","name":"scan_graph","read_only":true,"signature":"","version":"v1"}},{"plugin_description":{"code_type":"cpp","description":"standard","name":"standard","read_only":true,"signature":"","version":"v1"}}] +CALL db.listLabelIndexes('Person', 'vertex'); +[{"field":"birthyear","label":"Person","pair_unique":false,"unique":false},{"field":"name","label":"Person","pair_unique":false,"unique":true}] +CALL dbms.security.getUserPermissions('admin'); +[{"user_info":{"default":"FULL","demo2":"FULL","tgraph1":"FULL","tgraph2":"FULL","tgraph3":"FULL"}}] +CALL dbms.graph.getGraphInfo('default'); +[{"configuration":{"description":"","max_size_GB":4096},"graph_name":"default"}] +CALL db.plugin.listPlugin('PY', 'any'); +[] +CALL db.plugin.loadPlugin('PY','countPerson','ZGVmIFByb2Nlc3MoZGIsIGlucHV0KToKICAgIHR4biA9IGRiLkNyZWF0ZVJlYWRUeG4oKQogICAgaXQgPSB0eG4uR2V0VmVydGV4SXRlcmF0b3IoKQogICAgbiA9IDAKICAgIHdoaWxlIGl0LklzVmFsaWQoKToKICAgICAgICBpZiBpdC5HZXRMYWJlbCgpID09ICdQZXJzb24nOgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICBpdC5OZXh0KCkKICAgIHJldHVybiAoVHJ1ZSwgc3RyKG4pKQ==','PY','count person',true, 'v1'); +[] +CALL db.plugin.listPlugin('PY', 'any'); +[{"plugin_description":{"code_type":"python","description":"count person","name":"countPerson","read_only":true,"signature":"","version":"v1"}}] +CALL db.plugin.getPluginInfo('PY','countPerson'); +[{"plugin_description":{"code_base64":"Not show code here.","code_type":"py","description":"count person","name":"countPerson","read_only":true,"version":""}}] +CALL db.plugin.getPluginInfo('PY','countPerson',true); +[{"plugin_description":{"code_base64":"ZGVmIFByb2Nlc3MoZGIsIGlucHV0KToKICAgIHR4biA9IGRiLkNyZWF0ZVJlYWRUeG4oKQogICAgaXQgPSB0eG4uR2V0VmVydGV4SXRlcmF0b3IoKQogICAgbiA9IDAKICAgIHdoaWxlIGl0LklzVmFsaWQoKToKICAgICAgICBpZiBpdC5HZXRMYWJlbCgpID09ICdQZXJzb24nOgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICBpdC5OZXh0KCkKICAgIHJldHVybiAoVHJ1ZSwgc3RyKG4pKQ==","code_type":"py","description":"count person","name":"countPerson","read_only":true,"version":""}}] +CALL dbms.task.listTasks(); +[] +CALL plugin.cpp.scan_graph({scan_edges:true,times:2}); +[{"plugin.cpp.scan_graph":{"num_edges":56,"num_vertices":42}}] +CALL plugin.cpp.standard({}); +[{"bool_var":true,"double_var":123.23300170898438,"edge_num":{"in_num_edges":1,"out_num_edges":3},"edge_num_sum":4,"float_var":123.233,"in_edge":{"dst":20,"forward":true,"identity":0,"label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},"list_var":["1"],"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"out_edge":{"dst":14,"forward":true,"identity":0,"label_id":2,"properties":{"reg_time":"2023-05-01 12:00:00","weight":19.93},"src":12,"temporal_id":0},"path":[{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},{"dst":1,"forward":true,"identity":1,"label_id":1,"src":0,"temporal_id":0},{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}]}] +CALL dbms.procedures() YIELD name RETURN name,1; +[{"1":1,"name":"db.subgraph"},{"1":1,"name":"db.vertexLabels"},{"1":1,"name":"db.edgeLabels"},{"1":1,"name":"db.indexes"},{"1":1,"name":"db.listLabelIndexes"},{"1":1,"name":"db.propertyKeys"},{"1":1,"name":"db.warmup"},{"1":1,"name":"db.createVertexLabelByJson"},{"1":1,"name":"db.createEdgeLabelByJson"},{"1":1,"name":"db.createVertexLabel"},{"1":1,"name":"db.createLabel"},{"1":1,"name":"db.getLabelSchema"},{"1":1,"name":"db.getVertexSchema"},{"1":1,"name":"db.getEdgeSchema"},{"1":1,"name":"db.deleteLabel"},{"1":1,"name":"db.alterLabelDelFields"},{"1":1,"name":"db.alterLabelAddFields"},{"1":1,"name":"db.upsertVertex"},{"1":1,"name":"db.upsertVertexByJson"},{"1":1,"name":"db.upsertEdge"},{"1":1,"name":"db.upsertEdgeByJson"},{"1":1,"name":"db.alterLabelModFields"},{"1":1,"name":"db.createEdgeLabel"},{"1":1,"name":"db.addIndex"},{"1":1,"name":"db.addEdgeIndex"},{"1":1,"name":"db.addFullTextIndex"},{"1":1,"name":"db.deleteFullTextIndex"},{"1":1,"name":"db.rebuildFullTextIndex"},{"1":1,"name":"db.fullTextIndexes"},{"1":1,"name":"db.addEdgeConstraints"},{"1":1,"name":"db.clearEdgeConstraints"},{"1":1,"name":"dbms.procedures"},{"1":1,"name":"dbms.meta.countDetail"},{"1":1,"name":"dbms.meta.count"},{"1":1,"name":"dbms.meta.refreshCount"},{"1":1,"name":"dbms.security.changePassword"},{"1":1,"name":"dbms.security.changeUserPassword"},{"1":1,"name":"dbms.security.createUser"},{"1":1,"name":"dbms.security.deleteUser"},{"1":1,"name":"dbms.security.setUserMemoryLimit"},{"1":1,"name":"dbms.security.listUsers"},{"1":1,"name":"dbms.security.showCurrentUser"},{"1":1,"name":"dbms.security.listAllowedHosts"},{"1":1,"name":"dbms.security.deleteAllowedHosts"},{"1":1,"name":"dbms.security.addAllowedHosts"},{"1":1,"name":"dbms.graph.createGraph"},{"1":1,"name":"dbms.graph.deleteGraph"},{"1":1,"name":"dbms.graph.modGraph"},{"1":1,"name":"dbms.graph.listGraphs"},{"1":1,"name":"dbms.graph.listUserGraphs"},{"1":1,"name":"dbms.graph.getGraphInfo"},{"1":1,"name":"dbms.graph.getGraphSchema"},{"1":1,"name":"dbms.system.info"},{"1":1,"name":"dbms.config.list"},{"1":1,"name":"dbms.config.update"},{"1":1,"name":"dbms.takeSnapshot"},{"1":1,"name":"dbms.listBackupFiles"},{"1":1,"name":"algo.shortestPath"},{"1":1,"name":"algo.allShortestPaths"},{"1":1,"name":"algo.native.extract"},{"1":1,"name":"algo.pagerank"},{"1":1,"name":"algo.jaccard"},{"1":1,"name":"spatial.distance"},{"1":1,"name":"dbms.security.listRoles"},{"1":1,"name":"dbms.security.createRole"},{"1":1,"name":"dbms.security.deleteRole"},{"1":1,"name":"dbms.security.getUserInfo"},{"1":1,"name":"dbms.security.getUserMemoryUsage"},{"1":1,"name":"dbms.security.getUserPermissions"},{"1":1,"name":"dbms.security.getRoleInfo"},{"1":1,"name":"dbms.security.disableRole"},{"1":1,"name":"dbms.security.modRoleDesc"},{"1":1,"name":"dbms.security.rebuildRoleAccessLevel"},{"1":1,"name":"dbms.security.modRoleAccessLevel"},{"1":1,"name":"dbms.security.modRoleFieldAccessLevel"},{"1":1,"name":"dbms.security.disableUser"},{"1":1,"name":"dbms.security.setCurrentDesc"},{"1":1,"name":"dbms.security.setUserDesc"},{"1":1,"name":"dbms.security.deleteUserRoles"},{"1":1,"name":"dbms.security.rebuildUserRoles"},{"1":1,"name":"dbms.security.addUserRoles"},{"1":1,"name":"db.plugin.loadPlugin"},{"1":1,"name":"db.plugin.deletePlugin"},{"1":1,"name":"db.plugin.getPluginInfo"},{"1":1,"name":"db.plugin.listPlugin"},{"1":1,"name":"db.plugin.listUserPlugins"},{"1":1,"name":"db.plugin.callPlugin"},{"1":1,"name":"db.importor.dataImportor"},{"1":1,"name":"db.importor.fullImportor"},{"1":1,"name":"db.importor.fullFileImportor"},{"1":1,"name":"db.importor.schemaImportor"},{"1":1,"name":"db.deleteIndex"},{"1":1,"name":"db.deleteEdgeIndex"},{"1":1,"name":"db.flushDB"},{"1":1,"name":"db.dropDB"},{"1":1,"name":"dbms.task.listTasks"},{"1":1,"name":"dbms.task.terminateTask"},{"1":1,"name":"db.monitor.tuGraphInfo"},{"1":1,"name":"db.monitor.serverInfo"},{"1":1,"name":"dbms.ha.clusterInfo"}] +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Rachel Kempson'}) CALL algo.shortestPath(n1,n2) YIELD nodeCount,totalCost RETURN nodeCount,totalCost /* 2,1.0 */; +[{"nodeCount":2,"totalCost":1.0}] +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Rachel Kempson'}) CALL algo.shortestPath(n1,n2) YIELD path RETURN path /* [V[vid0],E[vid0_vid1_type_eid],V[vid1]] */; +[{"path":"[V[1],E[1_0_0_0_0],V[0]]"}] +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Houston'}) CALL algo.shortestPath(n1,n2) YIELD nodeCount,totalCost RETURN nodeCount,totalCost /* 6,5.0 */; +[{"nodeCount":6,"totalCost":5.0}] +MATCH (n1 {name:'Michael Redgrave'}),(n2:City) CALL algo.shortestPath(n1,n2) YIELD nodeCount,totalCost RETURN n2.name,nodeCount,totalCost /* 3 results */; +[{"n2.name":"Houston","nodeCount":6,"totalCost":5.0},{"n2.name":"London","nodeCount":3,"totalCost":2.0},{"n2.name":"New York","nodeCount":4,"totalCost":3.0}] +MATCH (n1 {name:'Michael Redgrave'}),(n2:City) CALL algo.shortestPath(n1,n2,{maxHops:3}) YIELD nodeCount RETURN n2.name,nodeCount /* 2 results */; +[{"n2.name":"Houston","nodeCount":0},{"n2.name":"London","nodeCount":3},{"n2.name":"New York","nodeCount":4}] +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Rachel Kempson'}) CALL algo.shortestPath(n1,n2,{relationshipQuery:'HAS_CHILD'}) YIELD nodeCount,totalCost RETURN nodeCount,totalCost /* 3,2.0 */; +[{"nodeCount":3,"totalCost":2.0}] +MATCH (n1 {name:'Corin Redgrave'}),(n2 {name:'London'}) CALL algo.allShortestPaths(n1,n2) YIELD nodeIds,cost RETURN nodeIds,cost /* 2 */; +[{"cost":3.0,"nodeIds":[3,0,2,14]},{"cost":3.0,"nodeIds":[3,1,2,14]}] +MATCH (n1 {name:'Corin Redgrave'}),(n2 {name:'Liam Neeson'}) CALL algo.allShortestPaths(n1,n2) YIELD nodeIds,cost RETURN nodeIds,cost /* 4 */; +[{"cost":4.0,"nodeIds":[3,0,2,5,4]},{"cost":4.0,"nodeIds":[3,0,2,5,4]},{"cost":4.0,"nodeIds":[3,1,2,5,4]},{"cost":4.0,"nodeIds":[3,1,2,5,4]}] +MATCH (n1 {name:'Corin Redgrave'}),(n2 {name:'Liam Neeson'}) CALL algo.allShortestPaths(n1,n2) YIELD nodeIds,relationshipIds,cost RETURN nodeIds,relationshipIds,cost /* 4 */; +[{"cost":4.0,"nodeIds":[3,0,2,5,4],"relationshipIds":"[0_3_0_0_0,0_2_0_0_0,2_5_0_0_0,5_4_1_0_0]"},{"cost":4.0,"nodeIds":[3,0,2,5,4],"relationshipIds":"[0_3_0_0_0,0_2_0_0_0,2_5_0_0_0,4_5_1_0_0]"},{"cost":4.0,"nodeIds":[3,1,2,5,4],"relationshipIds":"[1_3_0_0_0,1_2_0_0_0,2_5_0_0_0,5_4_1_0_0]"},{"cost":4.0,"nodeIds":[3,1,2,5,4],"relationshipIds":"[1_3_0_0_0,1_2_0_0_0,2_5_0_0_0,4_5_1_0_0]"}] +CALL algo.pagerank(10) YIELD node, pr RETURN node, pr ORDER by pr desc LIMIT 1 /* V[9], 0.0187 */; +[{"node":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"pr":0.018702394545433147}] +CALL algo.pagerank(10) YIELD node, pr RETURN node.name, pr LIMIT 1 /* Rachel Kempson0.010590751202103139 */; +[{"node.name":"Rachel Kempson","pr":0.010590751202103139}] +CALL algo.pagerank(10) YIELD node, pr with node MATCH(node)-[r]->(n)return node, r, n LIMIT 1/* V[0] E[0_2_0_0] E[0_2_0_0] V[2] */; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0}}] +CALL dbms.procedures() YIELD name, signature WHERE name='db.subgraph' RETURN signature; +[{"signature":"db.subgraph(vids::LIST) :: (subgraph::STRING)"}] +CALL dbms.meta.count(); +[{"number":21,"type":"vertex"},{"number":28,"type":"edge"}] +CALL dbms.meta.countDetail(); +[{"count":13,"is_vertex":true,"label":"Person"},{"count":3,"is_vertex":true,"label":"City"},{"count":5,"is_vertex":true,"label":"Film"},{"count":0,"is_vertex":true,"label":"Director"},{"count":0,"is_vertex":true,"label":"P2"},{"count":7,"is_vertex":false,"label":"HAS_CHILD"},{"count":4,"is_vertex":false,"label":"MARRIED"},{"count":6,"is_vertex":false,"label":"BORN_IN"},{"count":1,"is_vertex":false,"label":"DIRECTED"},{"count":2,"is_vertex":false,"label":"WROTE_MUSIC_FOR"},{"count":8,"is_vertex":false,"label":"ACTED_IN"},{"count":0,"is_vertex":false,"label":"LIKE"}] +CALL dbms.meta.refreshCount(); +[] +MATCH (a:Person {name: "Christopher Nolan"}), (b:Person {name: "Corin Redgrave"}) CALL plugin.cpp.custom_shortestpath(a, b) YIELD length, nodeIds RETURN length, nodeIds AS path; +[InputError] yield item [length] is not exist +CALL plugin.cpp.custom_pagerank(10) YIELD node, weight WITH node, weight MATCH(node)-[r]->(n) RETURN node, r, n, weight; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},"weight":0.041396665638497074},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},"weight":0.041396665638497074},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},"weight":0.041396665638497074},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},"weight":0.06339128766166077},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},"weight":0.06339128766166077},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},"weight":0.06339128766166077},{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":16,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},"weight":0.06339128766166077},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"node":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":5,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},"weight":0.05312535887800024},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"node":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},"weight":0.05312535887800024},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"node":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},"weight":0.05312535887800024},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"node":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"r":{"dst":9,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},"weight":0.05312535887800024},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"node":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"r":{"dst":5,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":4,"temporal_id":0},"weight":0.04559357278255597},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"node":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"r":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0},"weight":0.04559357278255597},{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"node":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"r":{"dst":4,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":5,"temporal_id":0},"weight":0.062354001093837486},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"node":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 11:00:00","weight":20.18},"src":5,"temporal_id":0},"weight":0.062354001093837486},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"node":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Liz James"},"src":5,"temporal_id":0},"weight":0.062354001093837486},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"node":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"r":{"dst":18,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Albus Dumbledore"},"src":6,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"node":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"King Arthur"},"src":6,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"node":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"r":{"dst":15,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 13:00:00","weight":19.11},"src":7,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"node":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Nick Parker"},"src":7,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":13,"label":"City","properties":{"name":"New York"}},"node":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"r":{"dst":13,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 14:00:00","weight":20.62},"src":8,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"node":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Halle/Annie"},"src":8,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"node":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"r":{"dst":1,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":10,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":13,"label":"City","properties":{"name":"New York"}},"node":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"r":{"dst":13,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 15:00:00","weight":20.55},"src":11,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"node":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"r":{"dst":16,"forward":false,"identity":0,"label":"WROTE_MUSIC_FOR","label_id":4,"src":11,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"node":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"r":{"dst":18,"forward":false,"identity":0,"label":"WROTE_MUSIC_FOR","label_id":4,"src":11,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"node":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 12:00:00","weight":19.93},"src":12,"temporal_id":0},"weight":0.02792564663114943},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"node":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"r":{"dst":17,"forward":false,"identity":0,"label":"DIRECTED","label_id":3,"src":12,"temporal_id":0},"weight":0.02792564663114943}] +MATCH (a:Person {name: "Christopher Nolan"}), (b:Person {name: "Corin Redgrave"}) CALL plugin.cpp.custom_shortestpath(a, b) YIELD length, nodeIds WITH length, nodeIds UNWIND nodeIds AS id RETURN id, length; +[InputError] yield item [length] is not exist +CALL plugin.cpp.peek_some_node_salt(10) YIELD node, salt WITH node, salt MATCH(node)-[r]->(n) RETURN node, r, n, salt; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},"salt":0.0},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0},"salt":0.0},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"node":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"r":{"dst":1,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":0,"temporal_id":0},"salt":0.0},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},"salt":20.23},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":3,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0},"salt":20.23},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":0,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":1,"temporal_id":0},"salt":20.23},{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"node":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"r":{"dst":16,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"The Headmaster"},"src":1,"temporal_id":0},"salt":20.23},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"node":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":5,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0},"salt":40.46},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"node":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0},"salt":40.46},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"node":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0},"salt":40.46},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}},"node":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"r":{"dst":9,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":3,"temporal_id":0},"salt":60.69},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"node":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"r":{"dst":5,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":4,"temporal_id":0},"salt":80.92},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"node":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"r":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0},"salt":80.92},{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"node":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"r":{"dst":4,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":5,"temporal_id":0},"salt":101.15},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"node":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"r":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 11:00:00","weight":20.18},"src":5,"temporal_id":0},"salt":101.15},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"node":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Liz James"},"src":5,"temporal_id":0},"salt":101.15},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"node":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"r":{"dst":18,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Albus Dumbledore"},"src":6,"temporal_id":0},"salt":121.38},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"node":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"r":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"King Arthur"},"src":6,"temporal_id":0},"salt":121.38},{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"node":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"r":{"dst":15,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 13:00:00","weight":19.11},"src":7,"temporal_id":0},"salt":141.61},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"node":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Nick Parker"},"src":7,"temporal_id":0},"salt":141.61},{"n":{"identity":13,"label":"City","properties":{"name":"New York"}},"node":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"r":{"dst":13,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 14:00:00","weight":20.62},"src":8,"temporal_id":0},"salt":161.84},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"node":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"r":{"dst":19,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Halle/Annie"},"src":8,"temporal_id":0},"salt":161.84}] +MATCH p = (n {name:"Rachel Kempson"})-[*0..3]->() CALL plugin.cpp.custom_path_process(nodes(p)) YIELD idSum RETURN idSum; +[{"idSum":0},{"idSum":2},{"idSum":3},{"idSum":1},{"idSum":7},{"idSum":16},{"idSum":22},{"idSum":12},{"idSum":3},{"idSum":4},{"idSum":1},{"idSum":17},{"idSum":11},{"idSum":21},{"idSum":26},{"idSum":8},{"idSum":17},{"idSum":23},{"idSum":13},{"idSum":3},{"idSum":4}] +CALL plugin.cpp.custom_algo() YIELD res RETURN res; +[{"res":"custom algo result"}] +CALL plugin.cpp.custom_algo(); +[{"res":"custom algo result"}] diff --git a/test/resource/unit_test/procedure/cypher/procedure.test b/test/resource/unit_test/procedure/cypher/procedure.test new file mode 100644 index 0000000000..cb41d2bd63 --- /dev/null +++ b/test/resource/unit_test/procedure/cypher/procedure.test @@ -0,0 +1,107 @@ +-- loadProcedure scan_graph ../../test/test_procedures/scan_graph.cpp read_only=true +-- loadProcedure standard ../../test/test_procedures/standard_result.cpp read_only=true +-- loadProcedure custom_shortestpath ../../test/test_procedures/v2_path_process.cpp read_only=true +-- loadProcedure custom_pagerank ../../test/test_procedures/v2_pagerank.cpp read_only=true +-- loadProcedure peek_some_node_salt ../../test/test_procedures/peek_some_node_salt.cpp read_only=true +-- loadProcedure custom_path_process ../../test/test_procedures/v2_path_process.cpp read_only=true +-- loadProcedure custom_algo ../../test/test_procedures/v2_algo.cpp read_only=true + +CALL db.createVertexLabel('Director', 'name', 'name', 'STRING', false, 'age', 'INT16', true); +CALL db.createVertexLabel('P2', 'flag1', 'flag1', 'BOOL', false, 'flag2', 'Bool', true); +CALL db.createEdgeLabel('LIKE', '[]'); +CALL db.addIndex('Person', 'birthyear', false); +CAll db.subgraph([1,2,3]); +CALL db.vertexLabels; +CALL db.edgeLabels; +CALL db.indexes; +CALL dbms.procedures; +CALL dbms.procedures YIELD signature; +CALL dbms.procedures YIELD signature, name; +CALL dbms.graph.createGraph('demo1'); +CALL dbms.graph.listGraphs(); +CALL dbms.graph.deleteGraph('demo1'); +CALL dbms.graph.listGraphs(); +CALL dbms.security.showCurrentUser(); +CALL dbms.security.changePassword('73@TuGraph','000'); +CALL dbms.security.changePassword('000','73@TuGraph'); +CALL dbms.security.createUser('guest1','123'); +CALL dbms.security.listUsers(); +CALL dbms.security.changeUserPassword('guest1','abc'); +CALL dbms.security.listUsers(); +CALL dbms.security.deleteUser('guest1'); +CALL dbms.security.listUsers(); +CALL dbms.graph.createGraph('demo2'); +CALL dbms.security.createUser('guest2','123'); +CALL dbms.system.info(); +CALL dbms.config.list(); +CALL dbms.security.listAllowedHosts(); +CALL dbms.security.addAllowedHosts('192.168.1.2', '192.168.1.3'); +CALL dbms.security.deleteAllowedHosts('192.168.1.2'); +CALL dbms.security.createUser('guest1','123'); +CALL dbms.security.getUserInfo('guest1'); +CALL dbms.security.listRoles(); +CALL dbms.security.createRole('test_role', 'test desc'); +CALL dbms.security.getRoleInfo('test_role'); +CALL dbms.security.modRoleDesc('test_role', 'modify test desc'); +CALL dbms.security.disableRole('test_role', true); +CALL dbms.security.getRoleInfo('test_role'); +CALL dbms.security.disableRole('test_role', false); +CALL dbms.graph.createGraph('tgraph1', 'test graph tgraph1', 1); +CALL dbms.graph.createGraph('tgraph2', 'test graph tgraph2', 2); +CALL dbms.graph.createGraph('tgraph3', 'test graph tgraph3', 3); +CALL dbms.security.rebuildRoleAccessLevel('test_role', {tgraph1: 'READ', tgraph2: 'WRITE', tgraph3: 'FULL'}); +CALL dbms.security.getRoleInfo('test_role'); +CALL dbms.security.modRoleAccessLevel('test_role', {tgraph1: 'NONE', tgraph2: 'NONE', tgraph3: 'WRITE'}); +CALL dbms.security.getRoleInfo('test_role'); +CALL dbms.security.disableUser('guest1', true); +CALL dbms.security.setUserDesc('guest1', 'modify guest1 desc'); +CALL dbms.security.setCurrentDesc('modify root desc'); +CALL dbms.security.listUsers(); +CALL dbms.security.createRole('test_role1', 'test desc'); +CALL dbms.security.createRole('test_role2', 'test desc'); +CALL dbms.security.createRole('test_role3', 'test desc'); +CALL dbms.security.listRoles(); +CALL dbms.security.rebuildUserRoles('guest1', ['test_role1', 'test_role2', 'test_role3']); +CALL dbms.security.listUsers(); +CALL dbms.security.deleteUserRoles('guest1', ['test_role2', 'test_role3']); +CALL dbms.security.listUsers(); +CALL dbms.security.addUserRoles('guest1', ['test_role2', 'test_role3']); +CALL dbms.security.listUsers(); +CALL dbms.security.deleteRole('test_role'); +CALL dbms.security.deleteUser('guest1'); +CALL db.plugin.listPlugin('CPP', 'any'); +CALL db.listLabelIndexes('Person', 'vertex'); +CALL dbms.security.getUserPermissions('admin'); +CALL dbms.graph.getGraphInfo('default'); +CALL db.plugin.listPlugin('PY', 'any'); +CALL db.plugin.loadPlugin('PY','countPerson','ZGVmIFByb2Nlc3MoZGIsIGlucHV0KToKICAgIHR4biA9IGRiLkNyZWF0ZVJlYWRUeG4oKQogICAgaXQgPSB0eG4uR2V0VmVydGV4SXRlcmF0b3IoKQogICAgbiA9IDAKICAgIHdoaWxlIGl0LklzVmFsaWQoKToKICAgICAgICBpZiBpdC5HZXRMYWJlbCgpID09ICdQZXJzb24nOgogICAgICAgICAgICBuID0gbiArIDEKICAgICAgICBpdC5OZXh0KCkKICAgIHJldHVybiAoVHJ1ZSwgc3RyKG4pKQ==','PY','count person',true, 'v1'); +CALL db.plugin.listPlugin('PY', 'any'); +CALL db.plugin.getPluginInfo('PY','countPerson'); +CALL db.plugin.getPluginInfo('PY','countPerson',true); +CALL dbms.task.listTasks(); +CALL plugin.cpp.scan_graph({scan_edges:true,times:2}); +CALL plugin.cpp.standard({}); +CALL dbms.procedures() YIELD name RETURN name,1; +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Rachel Kempson'}) CALL algo.shortestPath(n1,n2) YIELD nodeCount,totalCost RETURN nodeCount,totalCost /* 2,1.0 */; +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Rachel Kempson'}) CALL algo.shortestPath(n1,n2) YIELD path RETURN path /* [V[vid0],E[vid0_vid1_type_eid],V[vid1]] */; +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Houston'}) CALL algo.shortestPath(n1,n2) YIELD nodeCount,totalCost RETURN nodeCount,totalCost /* 6,5.0 */; +MATCH (n1 {name:'Michael Redgrave'}),(n2:City) CALL algo.shortestPath(n1,n2) YIELD nodeCount,totalCost RETURN n2.name,nodeCount,totalCost /* 3 results */; +MATCH (n1 {name:'Michael Redgrave'}),(n2:City) CALL algo.shortestPath(n1,n2,{maxHops:3}) YIELD nodeCount RETURN n2.name,nodeCount /* 2 results */; +MATCH (n1 {name:'Michael Redgrave'}),(n2 {name:'Rachel Kempson'}) CALL algo.shortestPath(n1,n2,{relationshipQuery:'HAS_CHILD'}) YIELD nodeCount,totalCost RETURN nodeCount,totalCost /* 3,2.0 */; +MATCH (n1 {name:'Corin Redgrave'}),(n2 {name:'London'}) CALL algo.allShortestPaths(n1,n2) YIELD nodeIds,cost RETURN nodeIds,cost /* 2 */; +MATCH (n1 {name:'Corin Redgrave'}),(n2 {name:'Liam Neeson'}) CALL algo.allShortestPaths(n1,n2) YIELD nodeIds,cost RETURN nodeIds,cost /* 4 */; +MATCH (n1 {name:'Corin Redgrave'}),(n2 {name:'Liam Neeson'}) CALL algo.allShortestPaths(n1,n2) YIELD nodeIds,relationshipIds,cost RETURN nodeIds,relationshipIds,cost /* 4 */; +CALL algo.pagerank(10) YIELD node, pr RETURN node, pr ORDER by pr desc LIMIT 1 /* V[9], 0.0187 */; +CALL algo.pagerank(10) YIELD node, pr RETURN node.name, pr LIMIT 1 /* Rachel Kempson0.010590751202103139 */; +CALL algo.pagerank(10) YIELD node, pr with node MATCH(node)-[r]->(n)return node, r, n LIMIT 1/* V[0] E[0_2_0_0] E[0_2_0_0] V[2] */; +CALL dbms.procedures() YIELD name, signature WHERE name='db.subgraph' RETURN signature; +CALL dbms.meta.count(); +CALL dbms.meta.countDetail(); +CALL dbms.meta.refreshCount(); +MATCH (a:Person {name: "Christopher Nolan"}), (b:Person {name: "Corin Redgrave"}) CALL plugin.cpp.custom_shortestpath(a, b) YIELD length, nodeIds RETURN length, nodeIds AS path; +CALL plugin.cpp.custom_pagerank(10) YIELD node, weight WITH node, weight MATCH(node)-[r]->(n) RETURN node, r, n, weight; +MATCH (a:Person {name: "Christopher Nolan"}), (b:Person {name: "Corin Redgrave"}) CALL plugin.cpp.custom_shortestpath(a, b) YIELD length, nodeIds WITH length, nodeIds UNWIND nodeIds AS id RETURN id, length; +CALL plugin.cpp.peek_some_node_salt(10) YIELD node, salt WITH node, salt MATCH(node)-[r]->(n) RETURN node, r, n, salt; +MATCH p = (n {name:"Rachel Kempson"})-[*0..3]->() CALL plugin.cpp.custom_path_process(nodes(p)) YIELD idSum RETURN idSum; +CALL plugin.cpp.custom_algo() YIELD res RETURN res; +CALL plugin.cpp.custom_algo(); \ No newline at end of file diff --git a/test/resource/unit_test/profile/cypher/profile.result b/test/resource/unit_test/profile/cypher/profile.result new file mode 100644 index 0000000000..99a8c2397b --- /dev/null +++ b/test/resource/unit_test/profile/cypher/profile.result @@ -0,0 +1,4 @@ +MATCH (n:Person) WHERE n.birthyear > 1960 RETURN n LIMIT 5; +[{"n":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] +PROFILE MATCH (n:Person) WHERE n.birthyear > 1960 RETURN n LIMIT 5; +[{"n":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] diff --git a/test/resource/unit_test/profile/cypher/profile.test b/test/resource/unit_test/profile/cypher/profile.test new file mode 100644 index 0000000000..70c9f85bc2 --- /dev/null +++ b/test/resource/unit_test/profile/cypher/profile.test @@ -0,0 +1,2 @@ +MATCH (n:Person) WHERE n.birthyear > 1960 RETURN n LIMIT 5; +PROFILE MATCH (n:Person) WHERE n.birthyear > 1960 RETURN n LIMIT 5; \ No newline at end of file diff --git a/test/resource/unit_test/query/cypher/query.result b/test/resource/unit_test/query/cypher/query.result new file mode 100644 index 0000000000..99ee27d01b --- /dev/null +++ b/test/resource/unit_test/query/cypher/query.result @@ -0,0 +1,110 @@ +MATCH (n:Person {name:'Vanessa Redgrave'})-[:ACTED_IN]->(m) RETURN n,m.title; +[{"m.title":"Camelot","n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (:Person {name:'Vanessa Redgrave'})-[:ACTED_IN]->(movie) return movie.title; +[{"movie.title":"Camelot"}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[relatedTo]-(b) RETURN b,relatedTo; +[{"b":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"relatedTo":{"dst":5,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0}},{"b":{"identity":14,"label":"City","properties":{"name":"London"}},"relatedTo":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0}},{"b":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"relatedTo":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0}},{"b":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"relatedTo":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0}},{"b":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"relatedTo":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0}}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD]-(b) RETURN b.name; +[{"b.name":"Natasha Richardson"},{"b.name":"Rachel Kempson"},{"b.name":"Michael Redgrave"}] +MATCH (m:Film {title:'Batman Begins'})<-[:DIRECTED]-(directors) RETURN directors.name; +[{"directors.name":"Christopher Nolan"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[]-(neighbors) RETURN neighbors; +[{"neighbors":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"neighbors":{"identity":14,"label":"City","properties":{"name":"London"}}},{"neighbors":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"neighbors":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"neighbors":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +MATCH (n:Person {name:'Lindsay Lohan'})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.name; +[{"coActors.name":"Natasha Richardson"},{"coActors.name":"Dennis Quaid"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[]->()<-[]-(m) RETURN m; +[{"m":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"m":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"m":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}}}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[]->()<-[]-(m) RETURN DISTINCT m; +[{"m":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"m":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}},{"m":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}}}] +MATCH (na)-[]->(nb)-[]->(nc) RETURN na,nb,nc; +[{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nc":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nc":{"identity":14,"label":"City","properties":{"name":"London"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nc":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"nc":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"na":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nc":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nc":{"identity":14,"label":"City","properties":{"name":"London"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nc":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}},"nc":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nc":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nc":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"na":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nb":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"nc":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"na":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"na":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":14,"label":"City","properties":{"name":"London"}}},{"na":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"na":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"na":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":14,"label":"City","properties":{"name":"London"}}},{"na":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"na":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nb":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"nc":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"na":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nb":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"nc":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"na":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"na":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"na":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"na":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}}] +MATCH (na:Person)-[:HAS_CHILD]->(nb)-[:MARRIED]->(nc) RETURN na,nb,nc; +[{"na":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}},"nb":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"nc":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"na":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"nb":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"nc":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +MATCH (m:Film {title:'Camelot'})<-[r:ACTED_IN]-(n) RETURN n.name,r.charactername; +[{"n.name":"Vanessa Redgrave","r.charactername":"Guenevere"},{"n.name":"Richard Harris","r.charactername":"King Arthur"}] +MATCH (n)-[relatedTo]->(vanessa:Person {name:'Vanessa Redgrave'}) RETURN n,relatedTo; +[{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"relatedTo":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":0,"temporal_id":0}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"relatedTo":{"dst":2,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":1,"temporal_id":0}}] +MATCH (n)<-[relatedTo]-(vanessa:Person {name:'Vanessa Redgrave'}) RETURN n,relatedTo; +[{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"relatedTo":{"dst":5,"forward":false,"identity":0,"label":"HAS_CHILD","label_id":0,"src":2,"temporal_id":0}},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"relatedTo":{"dst":14,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":"2023-05-01 10:00:00","weight":20.21},"src":2,"temporal_id":0}},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"relatedTo":{"dst":20,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Guenevere"},"src":2,"temporal_id":0}}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[]->(b:Person) RETURN b.name; +[{"b.name":"Natasha Richardson"}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b:Person) RETURN b.name; +[{"b.name":"Natasha Richardson"},{"b.name":"Rachel Kempson"},{"b.name":"Michael Redgrave"}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b) WHERE b:Person RETURN b.name; +[{"b.name":"Natasha Richardson"},{"b.name":"Rachel Kempson"},{"b.name":"Michael Redgrave"}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b) WHERE b:Person AND b.birthyear >= 1910 RETURN b.name; +[{"b.name":"Natasha Richardson"},{"b.name":"Rachel Kempson"}] +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b) WHERE b:Person OR b:City RETURN b.name; +[{"b.name":"Natasha Richardson"},{"b.name":"London"},{"b.name":"Rachel Kempson"},{"b.name":"Michael Redgrave"}] +MATCH (n:Person {name:'Lindsay Lohan'})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors)-[:BORN_IN]->(city) RETURN coActors.name,city.name; +[{"city.name":"London","coActors.name":"Natasha Richardson"},{"city.name":"Houston","coActors.name":"Dennis Quaid"}] +MATCH (a)-->(b)-->(c)<--(d) USING JOIN ON c WHERE a.uid > 1 AND d.uid > 2 AND b.uid < 3 AND c.uid < 4 RETURN d; +[] +MATCH (a)-->(b)-->(c)<--(d) WHERE a.uid > 1 AND d.uid > 2 AND b.uid < 3 AND c.uid < 4 RETURN d; +[] +MATCH (a)-->(b)-->(c)<--(d) WHERE a.uid > d.uid AND b.uid < c.uid RETURN d; +[] +MATCH (a)-->(b)-->(c)<--(d) WHERE a.uid > d.uid AND b.uid < c.uid AND a.uid > b.uid RETURN d; +[] +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE b.weight < 20.18 RETURN m; +[{"m":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}}}] +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE b.weight < 20.18 AND m.name <> 'Houston' RETURN m; +[{"m":{"identity":14,"label":"City","properties":{"name":"London"}}}] +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = a.title RETURN n; +[] +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE a.role = "Iron Man" RETURN n; +[] +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = "Vanessa Redgrave" RETURN n; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE m.title = "Camelot" RETURN n; +[{"n":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = a.title AND m.title = "Camelot" RETURN n; +[] +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = "Vanessa Redgrave" AND m.title = a.title RETURN n; +[] +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE b.weight < 19.2 OR b.weight > 20.6 RETURN m; +[{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}}}] +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE (b.weight + b.weight) < 38.4 OR b.weight > 20.6 RETURN m; +[{"m":{"identity":15,"label":"City","properties":{"name":"Houston"}}},{"m":{"identity":13,"label":"City","properties":{"name":"New York"}}}] +MATCH (a)-[e]->(b) WHERE a.name='Liam Neeson' and b.title<>'' and (e.charactername='Henri Ducard' or e.relation = '') RETURN a,e,b; +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"e":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0}}] +MATCH (a) WHERE a.name IN ['Dennis Quaid', 'Christopher Nolan'] WITH a MATCH (b) WHERE b.name IN ['London'] RETURN a, b; +[{"a":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}}},{"a":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}}}] +MATCH (a) WHERE a.name IN ['Dennis Quaid', 'Christopher Nolan'] WITH a MATCH (b) WHERE b.name IN ['London', 'Beijing', 'Houston'] RETURN a, b; +[{"a":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}}},{"a":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"b":{"identity":15,"label":"City","properties":{"name":"Houston"}}},{"a":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}}},{"a":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}},"b":{"identity":15,"label":"City","properties":{"name":"Houston"}}}] +MATCH (n:Person) WHERE n.name = 'Vanessa Redgrave' OR NOT n.name <> 'Dennis Quaid' RETURN n.name; +[{"n.name":"Dennis Quaid"},{"n.name":"Vanessa Redgrave"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[:BORN_IN|ACTED_IN]->(m) RETURN m; +[{"m":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +MATCH (n:Person {name:'Michael Redgrave'})<-[:MARRIED|HAS_CHILD]-(m) RETURN m; +[{"m":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[:BORN_IN|HAS_CHILD]-(m) RETURN m; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +MATCH (n:Person {name:'Vanessa Redgrave'})--(m:Person) WHERE m.birthyear > n.birthyear RETURN m; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] +MATCH (n:Person {name:'Vanessa Redgrave'})--(m:Person) WHERE n.birthyear > m.birthyear RETURN m; +[{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +MATCH (n:Person {name:'Natasha Richardson'})-[:HAS_CHILD]->(m) RETURN m; +[] +MATCH (n:Person {name:'Natasha Richardson'})<-[:HAS_CHILD]-(m) RETURN m; +[{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (n:Person {name:'Natasha Richardson'})-[:HAS_CHILD]-(m) RETURN m; +[{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +match (a)-->(b)-->(c)<--(d) where not ((not (a.birthyear>d.birthyear and b.birthyearb.birthyear)) return d; +[{"d":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"d":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"d":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}}},{"d":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"d":{"identity":12,"label":"Person","properties":{"birthyear":1970,"name":"Christopher Nolan"}}}] +MATCH (n:Person{name:'Vanessa Redgrave'}),(m:Person{name: 'Michael Redgrave'}) WHERE n.birthyear > 1960 and m.birthyear < 2000 RETURN n.name LIMIT 1; +[] +MATCH (n:Person) RETURN count(n); +[{"count(n)":13}] +MATCH (n:Person) WHERE n.birthyear > 1900 AND n.birthyear < 2000 RETURN count(n); +[{"count(n)":12}] +MATCH (n:Person) RETURN n.birthyear, count(n); +[{"count(n)":1,"n.birthyear":1873},{"count(n)":1,"n.birthyear":1910},{"count(n)":1,"n.birthyear":1930},{"count(n)":1,"n.birthyear":1908},{"count(n)":1,"n.birthyear":1939},{"count(n)":1,"n.birthyear":1937},{"count(n)":1,"n.birthyear":1965},{"count(n)":1,"n.birthyear":1970},{"count(n)":1,"n.birthyear":1986},{"count(n)":1,"n.birthyear":1932},{"count(n)":1,"n.birthyear":1963},{"count(n)":1,"n.birthyear":1954},{"count(n)":1,"n.birthyear":1952}] +MATCH (f:Film)<-[:ACTED_IN]-(p:Person)-[:BORN_IN]->(c:City) RETURN c.name, count(f) AS sum ORDER BY sum DESC; +[{"c.name":"London","sum":2},{"c.name":"New York","sum":1},{"c.name":"Houston","sum":1}] +MATCH p=(n1)-[r1]->(n2)-[r2]->(m:Person) return count(p); +[{"count(p)":16}] +MATCH p1=(n1)-[r1]->(n2)-[r2]->(m1:City),p2=(n3)-[r3]->(m2:Film) return count(p1); +[{"count(p1)":44}] +MATCH p1=(n1)-[r1]->(n2)-[r2]->(m1:City) with count(p1) as cp match p1=(n1)-[r1]->(m1:Film) return count(p1); +[{"count(p1)":11}] diff --git a/test/resource/unit_test/query/cypher/query.test b/test/resource/unit_test/query/cypher/query.test new file mode 100644 index 0000000000..84d6bdd2c8 --- /dev/null +++ b/test/resource/unit_test/query/cypher/query.test @@ -0,0 +1,55 @@ +MATCH (n:Person {name:'Vanessa Redgrave'})-[:ACTED_IN]->(m) RETURN n,m.title; +MATCH (:Person {name:'Vanessa Redgrave'})-[:ACTED_IN]->(movie) return movie.title; +MATCH (a:Person {name:'Vanessa Redgrave'})-[relatedTo]-(b) RETURN b,relatedTo; +MATCH (a:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD]-(b) RETURN b.name; +MATCH (m:Film {title:'Batman Begins'})<-[:DIRECTED]-(directors) RETURN directors.name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[]-(neighbors) RETURN neighbors; +MATCH (n:Person {name:'Lindsay Lohan'})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[]->()<-[]-(m) RETURN m; +MATCH (n:Person {name:'Vanessa Redgrave'})-[]->()<-[]-(m) RETURN DISTINCT m; +MATCH (na)-[]->(nb)-[]->(nc) RETURN na,nb,nc; +MATCH (na:Person)-[:HAS_CHILD]->(nb)-[:MARRIED]->(nc) RETURN na,nb,nc; +MATCH (m:Film {title:'Camelot'})<-[r:ACTED_IN]-(n) RETURN n.name,r.charactername; +MATCH (n)-[relatedTo]->(vanessa:Person {name:'Vanessa Redgrave'}) RETURN n,relatedTo; +MATCH (n)<-[relatedTo]-(vanessa:Person {name:'Vanessa Redgrave'}) RETURN n,relatedTo; +MATCH (a:Person {name:'Vanessa Redgrave'})-[]->(b:Person) RETURN b.name; +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b:Person) RETURN b.name; +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b) WHERE b:Person RETURN b.name; +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b) WHERE b:Person AND b.birthyear >= 1910 RETURN b.name; +MATCH (a:Person {name:'Vanessa Redgrave'})-[]-(b) WHERE b:Person OR b:City RETURN b.name; +MATCH (n:Person {name:'Lindsay Lohan'})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors)-[:BORN_IN]->(city) RETURN coActors.name,city.name; +MATCH (a)-->(b)-->(c)<--(d) USING JOIN ON c WHERE a.uid > 1 AND d.uid > 2 AND b.uid < 3 AND c.uid < 4 RETURN d; +MATCH (a)-->(b)-->(c)<--(d) WHERE a.uid > 1 AND d.uid > 2 AND b.uid < 3 AND c.uid < 4 RETURN d; +MATCH (a)-->(b)-->(c)<--(d) WHERE a.uid > d.uid AND b.uid < c.uid RETURN d; +MATCH (a)-->(b)-->(c)<--(d) WHERE a.uid > d.uid AND b.uid < c.uid AND a.uid > b.uid RETURN d; +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE b.weight < 20.18 RETURN m; +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE b.weight < 20.18 AND m.name <> 'Houston' RETURN m; +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = a.title RETURN n; +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE a.role = "Iron Man" RETURN n; +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = "Vanessa Redgrave" RETURN n; +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE m.title = "Camelot" RETURN n; +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = a.title AND m.title = "Camelot" RETURN n; +MATCH (n:Person)-[a:ACTED_IN]->(m) WHERE n.name = "Vanessa Redgrave" AND m.title = a.title RETURN n; +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE b.weight < 19.2 OR b.weight > 20.6 RETURN m; +MATCH (n:Person)-[b:BORN_IN]->(m) WHERE (b.weight + b.weight) < 38.4 OR b.weight > 20.6 RETURN m; +MATCH (a)-[e]->(b) WHERE a.name='Liam Neeson' and b.title<>'' and (e.charactername='Henri Ducard' or e.relation = '') RETURN a,e,b; +MATCH (a) WHERE a.name IN ['Dennis Quaid', 'Christopher Nolan'] WITH a MATCH (b) WHERE b.name IN ['London'] RETURN a, b; +MATCH (a) WHERE a.name IN ['Dennis Quaid', 'Christopher Nolan'] WITH a MATCH (b) WHERE b.name IN ['London', 'Beijing', 'Houston'] RETURN a, b; +MATCH (n:Person) WHERE n.name = 'Vanessa Redgrave' OR NOT n.name <> 'Dennis Quaid' RETURN n.name; +MATCH (n:Person {name:'Vanessa Redgrave'})-[:BORN_IN|ACTED_IN]->(m) RETURN m; +MATCH (n:Person {name:'Michael Redgrave'})<-[:MARRIED|HAS_CHILD]-(m) RETURN m; +MATCH (n:Person {name:'Vanessa Redgrave'})-[:BORN_IN|HAS_CHILD]-(m) RETURN m; +MATCH (n:Person {name:'Vanessa Redgrave'})--(m:Person) WHERE m.birthyear > n.birthyear RETURN m; +MATCH (n:Person {name:'Vanessa Redgrave'})--(m:Person) WHERE n.birthyear > m.birthyear RETURN m; +MATCH (n:Person {name:'Natasha Richardson'})-[:HAS_CHILD]->(m) RETURN m; +MATCH (n:Person {name:'Natasha Richardson'})<-[:HAS_CHILD]-(m) RETURN m; +MATCH (n:Person {name:'Natasha Richardson'})-[:HAS_CHILD]-(m) RETURN m; +match (a)-->(b)-->(c)<--(d) where not ((not (a.birthyear>d.birthyear and b.birthyearb.birthyear)) return d; +MATCH (n:Person{name:'Vanessa Redgrave'}),(m:Person{name: 'Michael Redgrave'}) WHERE n.birthyear > 1960 and m.birthyear < 2000 RETURN n.name LIMIT 1; +MATCH (n:Person) RETURN count(n); +MATCH (n:Person) WHERE n.birthyear > 1900 AND n.birthyear < 2000 RETURN count(n); +MATCH (n:Person) RETURN n.birthyear, count(n); +MATCH (f:Film)<-[:ACTED_IN]-(p:Person)-[:BORN_IN]->(c:City) RETURN c.name, count(f) AS sum ORDER BY sum DESC; +MATCH p=(n1)-[r1]->(n2)-[r2]->(m:Person) return count(p); +MATCH p1=(n1)-[r1]->(n2)-[r2]->(m1:City),p2=(n3)-[r3]->(m2:Film) return count(p1); +MATCH p1=(n1)-[r1]->(n2)-[r2]->(m1:City) with count(p1) as cp match p1=(n1)-[r1]->(m1:Film) return count(p1); \ No newline at end of file diff --git a/test/resource/unit_test/remove/cypher/remove.result b/test/resource/unit_test/remove/cypher/remove.result new file mode 100644 index 0000000000..b30a90d43b --- /dev/null +++ b/test/resource/unit_test/remove/cypher/remove.result @@ -0,0 +1,4 @@ +MATCH (a {name:'Liam Neeson'}) REMOVE a.birthyear RETURN a.name,a.birthyear; +[{"a.birthyear":null,"a.name":"Liam Neeson"}] +MATCH (a {name:'Liam Neeson'}) REMOVE a.name RETURN a.name,a.birthyear; +[FieldCannotBeSetNull] Field [name] is not optional. diff --git a/test/resource/unit_test/remove/cypher/remove.test b/test/resource/unit_test/remove/cypher/remove.test new file mode 100644 index 0000000000..16a2a99965 --- /dev/null +++ b/test/resource/unit_test/remove/cypher/remove.test @@ -0,0 +1,2 @@ +MATCH (a {name:'Liam Neeson'}) REMOVE a.birthyear RETURN a.name,a.birthyear; +MATCH (a {name:'Liam Neeson'}) REMOVE a.name RETURN a.name,a.birthyear; \ No newline at end of file diff --git a/test/resource/unit_test/set/cypher/set.result b/test/resource/unit_test/set/cypher/set.result new file mode 100644 index 0000000000..67386ad002 --- /dev/null +++ b/test/resource/unit_test/set/cypher/set.result @@ -0,0 +1,39 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'age', 'INT16', true, 'eyes', 'STRING', true, 'date', 'DATE', true); +[] +CALL db.createEdgeLabel('KNOWS', '[]', 'weight', 'INT16', true); +[] +CREATE (a:Person {name:'A', age:13, date:DATE('2023-07-23')}) CREATE (b:Person {name:'B', age:33, eyes:'blue'}) CREATE (c:Person {name:'C', age:44, eyes:'blue'}) CREATE (d:Person {name:'D', eyes:'brown'}) CREATE (e:Person {name:'E'}) CREATE (f:Person {name:'F', age:1}) CREATE (g:Person {name:'G', age:2}) CREATE (h:Person {name:'H', age:2}) CREATE (i1:Person {name:'I', age:3}) CREATE (a)-[:KNOWS {weight:10}]->(b), (a)-[:KNOWS {weight:15}]->(c), (a)-[:KNOWS {weight:40}]->(d), (b)-[:KNOWS {weight:20}]->(e), (c)-[:KNOWS {weight:12}]->(e),(f)-[:KNOWS {weight:0}]->(g), (f)-[:KNOWS {weight:0}]->(h),(f)-[:KNOWS {weight:0}]->(i1) ; +[{"":"created 9 vertices, created 8 edges."}] +MATCH (n:Person {name:'E'}) SET n.name='X'; +[{"":"set 1 properties."}] +#MATCH (n:Person {name:'A'}), (m:Person {name:'B'}) SET n.age=50 SET m.age=51; +MATCH (n:Person {name:'A'})-[e:KNOWS]->(m:Person) SET n.age=50 SET e.weight=50; +[{"":"set 6 properties."}] +MATCH (n:Person {name:'B'})<-[]-(m:Person) SET m.age = 34; +[{"":"set 1 properties."}] +MATCH (n:Person {name:'B'})<-[]-(m:Person) SET m.age = id(n); +[{"":"set 1 properties."}] +MATCH (n:Person {name:'B'})<-[]-(m:Person) SET m = {age: 33}; +[{"":"set 1 properties."}] +match (n) return n,properties(n) /*debug*/; +[{"n":{"identity":0,"label":"Person","properties":{"age":33,"date":"2023-07-23","eyes":null,"name":"A"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":0,\"age\":33,\"date\":2023-07-23,\"name\":\"A\",\"eyes\":NUL}"},{"n":{"identity":1,"label":"Person","properties":{"age":33,"date":null,"eyes":"blue","name":"B"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":1,\"age\":33,\"date\":NUL,\"name\":\"B\",\"eyes\":\"blue\"}"},{"n":{"identity":2,"label":"Person","properties":{"age":44,"date":null,"eyes":"blue","name":"C"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":2,\"age\":44,\"date\":NUL,\"name\":\"C\",\"eyes\":\"blue\"}"},{"n":{"identity":3,"label":"Person","properties":{"age":null,"date":null,"eyes":"brown","name":"D"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":3,\"age\":NUL,\"date\":NUL,\"name\":\"D\",\"eyes\":\"brown\"}"},{"n":{"identity":4,"label":"Person","properties":{"age":null,"date":null,"eyes":null,"name":"X"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":4,\"age\":NUL,\"date\":NUL,\"name\":\"X\",\"eyes\":NUL}"},{"n":{"identity":5,"label":"Person","properties":{"age":1,"date":null,"eyes":null,"name":"F"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":5,\"age\":1,\"date\":NUL,\"name\":\"F\",\"eyes\":NUL}"},{"n":{"identity":6,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"G"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":6,\"age\":2,\"date\":NUL,\"name\":\"G\",\"eyes\":NUL}"},{"n":{"identity":7,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"H"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":7,\"age\":2,\"date\":NUL,\"name\":\"H\",\"eyes\":NUL}"},{"n":{"identity":8,"label":"Person","properties":{"age":3,"date":null,"eyes":null,"name":"I"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":8,\"age\":3,\"date\":NUL,\"name\":\"I\",\"eyes\":NUL}"}] +match (n) return n,properties(n) /*debug*/; +[{"n":{"identity":0,"label":"Person","properties":{"age":33,"date":"2023-07-23","eyes":null,"name":"A"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":0,\"age\":33,\"date\":2023-07-23,\"name\":\"A\",\"eyes\":NUL}"},{"n":{"identity":1,"label":"Person","properties":{"age":33,"date":null,"eyes":"blue","name":"B"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":1,\"age\":33,\"date\":NUL,\"name\":\"B\",\"eyes\":\"blue\"}"},{"n":{"identity":2,"label":"Person","properties":{"age":44,"date":null,"eyes":"blue","name":"C"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":2,\"age\":44,\"date\":NUL,\"name\":\"C\",\"eyes\":\"blue\"}"},{"n":{"identity":3,"label":"Person","properties":{"age":null,"date":null,"eyes":"brown","name":"D"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":3,\"age\":NUL,\"date\":NUL,\"name\":\"D\",\"eyes\":\"brown\"}"},{"n":{"identity":4,"label":"Person","properties":{"age":null,"date":null,"eyes":null,"name":"X"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":4,\"age\":NUL,\"date\":NUL,\"name\":\"X\",\"eyes\":NUL}"},{"n":{"identity":5,"label":"Person","properties":{"age":1,"date":null,"eyes":null,"name":"F"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":5,\"age\":1,\"date\":NUL,\"name\":\"F\",\"eyes\":NUL}"},{"n":{"identity":6,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"G"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":6,\"age\":2,\"date\":NUL,\"name\":\"G\",\"eyes\":NUL}"},{"n":{"identity":7,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"H"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":7,\"age\":2,\"date\":NUL,\"name\":\"H\",\"eyes\":NUL}"},{"n":{"identity":8,"label":"Person","properties":{"age":3,"date":null,"eyes":null,"name":"I"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":8,\"age\":3,\"date\":NUL,\"name\":\"I\",\"eyes\":NUL}"}] +MATCH (n:Person {name:'X'}) SET n += {name:'Y', age:19}; +[{"":"set 2 properties."}] +match (n) return n,properties(n) /*debug*/; +[{"n":{"identity":0,"label":"Person","properties":{"age":33,"date":"2023-07-23","eyes":null,"name":"A"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":0,\"age\":33,\"date\":2023-07-23,\"name\":\"A\",\"eyes\":NUL}"},{"n":{"identity":1,"label":"Person","properties":{"age":33,"date":null,"eyes":"blue","name":"B"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":1,\"age\":33,\"date\":NUL,\"name\":\"B\",\"eyes\":\"blue\"}"},{"n":{"identity":2,"label":"Person","properties":{"age":44,"date":null,"eyes":"blue","name":"C"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":2,\"age\":44,\"date\":NUL,\"name\":\"C\",\"eyes\":\"blue\"}"},{"n":{"identity":3,"label":"Person","properties":{"age":null,"date":null,"eyes":"brown","name":"D"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":3,\"age\":NUL,\"date\":NUL,\"name\":\"D\",\"eyes\":\"brown\"}"},{"n":{"identity":4,"label":"Person","properties":{"age":19,"date":null,"eyes":null,"name":"Y"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":4,\"age\":19,\"date\":NUL,\"name\":\"Y\",\"eyes\":NUL}"},{"n":{"identity":5,"label":"Person","properties":{"age":1,"date":null,"eyes":null,"name":"F"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":5,\"age\":1,\"date\":NUL,\"name\":\"F\",\"eyes\":NUL}"},{"n":{"identity":6,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"G"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":6,\"age\":2,\"date\":NUL,\"name\":\"G\",\"eyes\":NUL}"},{"n":{"identity":7,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"H"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":7,\"age\":2,\"date\":NUL,\"name\":\"H\",\"eyes\":NUL}"},{"n":{"identity":8,"label":"Person","properties":{"age":3,"date":null,"eyes":null,"name":"I"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":8,\"age\":3,\"date\":NUL,\"name\":\"I\",\"eyes\":NUL}"}] +MATCH (n {name:'A'})-[r:KNOWS]->(m {name:'B'}) SET r.weight=11; +[{"":"set 1 properties."}] +MATCH (n)-[r:KNOWS]->(m) WHERE r.weight=15 SET r += {weight:16}; +[{"":"set 0 properties."}] +MATCH (n)-[r:KNOWS]->(m) WHERE r.weight=40 SET r.weight = r.weight + 1; +[{"":"set 0 properties."}] +MATCH (n)-[r:KNOWS]->(m) WHERE r.weight=20 SET r=NULL; +[{"":"set 1 properties."}] +match (n)-[r]->(m) return r,properties(r) /*debug*/; +[{"properties(r)":{"_EID_":"0_1_0_0_0","_LABEL_":"KNOWS","weight":11},"r":{"dst":1,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":11},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"0_2_0_0_0","_LABEL_":"KNOWS","weight":50},"r":{"dst":2,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":50},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"0_3_0_0_0","_LABEL_":"KNOWS","weight":50},"r":{"dst":3,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":50},"src":0,"temporal_id":0}},{"properties(r)":{"_EID_":"2_4_0_0_0","_LABEL_":"KNOWS","weight":12},"r":{"dst":4,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":12},"src":2,"temporal_id":0}},{"properties(r)":{"_EID_":"5_6_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":6,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}},{"properties(r)":{"_EID_":"5_7_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":7,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}},{"properties(r)":{"_EID_":"5_8_0_0_0","_LABEL_":"KNOWS","weight":0},"r":{"dst":8,"forward":false,"identity":0,"label":"KNOWS","label_id":0,"properties":{"weight":0},"src":5,"temporal_id":0}}] +MATCH (n:Person {name:'Y'}) SET n=NULL; +[{"":"set 1 properties."}] +match (n) return n,properties(n) /*debug*/; +[{"n":{"identity":0,"label":"Person","properties":{"age":33,"date":"2023-07-23","eyes":null,"name":"A"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":0,\"age\":33,\"date\":2023-07-23,\"name\":\"A\",\"eyes\":NUL}"},{"n":{"identity":1,"label":"Person","properties":{"age":33,"date":null,"eyes":"blue","name":"B"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":1,\"age\":33,\"date\":NUL,\"name\":\"B\",\"eyes\":\"blue\"}"},{"n":{"identity":2,"label":"Person","properties":{"age":44,"date":null,"eyes":"blue","name":"C"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":2,\"age\":44,\"date\":NUL,\"name\":\"C\",\"eyes\":\"blue\"}"},{"n":{"identity":3,"label":"Person","properties":{"age":null,"date":null,"eyes":"brown","name":"D"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":3,\"age\":NUL,\"date\":NUL,\"name\":\"D\",\"eyes\":\"brown\"}"},{"n":{"identity":5,"label":"Person","properties":{"age":1,"date":null,"eyes":null,"name":"F"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":5,\"age\":1,\"date\":NUL,\"name\":\"F\",\"eyes\":NUL}"},{"n":{"identity":6,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"G"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":6,\"age\":2,\"date\":NUL,\"name\":\"G\",\"eyes\":NUL}"},{"n":{"identity":7,"label":"Person","properties":{"age":2,"date":null,"eyes":null,"name":"H"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":7,\"age\":2,\"date\":NUL,\"name\":\"H\",\"eyes\":NUL}"},{"n":{"identity":8,"label":"Person","properties":{"age":3,"date":null,"eyes":null,"name":"I"}},"properties(n)":"{\"_LABEL_\":\"Person\",\"_VID_\":8,\"age\":3,\"date\":NUL,\"name\":\"I\",\"eyes\":NUL}"}] diff --git a/test/resource/unit_test/set/cypher/set.test b/test/resource/unit_test/set/cypher/set.test new file mode 100644 index 0000000000..9588fef2e4 --- /dev/null +++ b/test/resource/unit_test/set/cypher/set.test @@ -0,0 +1,20 @@ +CALL db.createVertexLabel('Person', 'name', 'name', 'STRING', false, 'age', 'INT16', true, 'eyes', 'STRING', true, 'date', 'DATE', true); +CALL db.createEdgeLabel('KNOWS', '[]', 'weight', 'INT16', true); +CREATE (a:Person {name:'A', age:13, date:DATE('2023-07-23')}) CREATE (b:Person {name:'B', age:33, eyes:'blue'}) CREATE (c:Person {name:'C', age:44, eyes:'blue'}) CREATE (d:Person {name:'D', eyes:'brown'}) CREATE (e:Person {name:'E'}) CREATE (f:Person {name:'F', age:1}) CREATE (g:Person {name:'G', age:2}) CREATE (h:Person {name:'H', age:2}) CREATE (i1:Person {name:'I', age:3}) CREATE (a)-[:KNOWS {weight:10}]->(b), (a)-[:KNOWS {weight:15}]->(c), (a)-[:KNOWS {weight:40}]->(d), (b)-[:KNOWS {weight:20}]->(e), (c)-[:KNOWS {weight:12}]->(e),(f)-[:KNOWS {weight:0}]->(g), (f)-[:KNOWS {weight:0}]->(h),(f)-[:KNOWS {weight:0}]->(i1) ; +MATCH (n:Person {name:'E'}) SET n.name='X'; +#MATCH (n:Person {name:'A'}), (m:Person {name:'B'}) SET n.age=50 SET m.age=51; +MATCH (n:Person {name:'A'})-[e:KNOWS]->(m:Person) SET n.age=50 SET e.weight=50; +MATCH (n:Person {name:'B'})<-[]-(m:Person) SET m.age = 34; +MATCH (n:Person {name:'B'})<-[]-(m:Person) SET m.age = id(n); +MATCH (n:Person {name:'B'})<-[]-(m:Person) SET m = {age: 33}; +match (n) return n,properties(n) /*debug*/; +match (n) return n,properties(n) /*debug*/; +MATCH (n:Person {name:'X'}) SET n += {name:'Y', age:19}; +match (n) return n,properties(n) /*debug*/; +MATCH (n {name:'A'})-[r:KNOWS]->(m {name:'B'}) SET r.weight=11; +MATCH (n)-[r:KNOWS]->(m) WHERE r.weight=15 SET r += {weight:16}; +MATCH (n)-[r:KNOWS]->(m) WHERE r.weight=40 SET r.weight = r.weight + 1; +MATCH (n)-[r:KNOWS]->(m) WHERE r.weight=20 SET r=NULL; +match (n)-[r]->(m) return r,properties(r) /*debug*/; +MATCH (n:Person {name:'Y'}) SET n=NULL; +match (n) return n,properties(n) /*debug*/; diff --git a/test/resource/unit_test/topn/cypher/topn.result b/test/resource/unit_test/topn/cypher/topn.result new file mode 100644 index 0000000000..4f5f326fbb --- /dev/null +++ b/test/resource/unit_test/topn/cypher/topn.result @@ -0,0 +1,14 @@ +MATCH (a:Person {name:'Lindsay Lohan'}), (b:Film {title:'The Parent Trap'}) CREATE (a)-[r:DIRECTED]->(b); +[{"":"created 0 vertices, created 1 edges."}] +match (v1:Film) return v1.title order by v1.title limit 3; +[{"v1.title":"Batman Begins"},{"v1.title":"Camelot"},{"v1.title":"Goodbye, Mr. Chips"}] +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,v2.name as cnt order by cnt desc limit 3; +[{"cnt":"Vanessa Redgrave","v1.title":"Camelot"},{"cnt":"Richard Harris","v1.title":"Camelot"},{"cnt":"Richard Harris","v1.title":"Harry Potter and the Sorcerer's Stone"}] +match (:Person {name:'Vanessa Redgrave'})<-[:HAS_CHILD]-(p)-[:ACTED_IN*0..]->(m) return p.name,m order by p.name limit 3; +[{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"p.name":"Michael Redgrave"},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"p.name":"Michael Redgrave"},{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}},"p.name":"Rachel Kempson"}] +MATCH (n) RETURN n.name AS name ORDER BY name LIMIT 10; +[{"name":null},{"name":null},{"name":null},{"name":null},{"name":null},{"name":"Christopher Nolan"},{"name":"Corin Redgrave"},{"name":"Dennis Quaid"},{"name":"Houston"},{"name":"Jemma Redgrave"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN m.birthyear, m.name ORDER BY m.name LIMIT 5; +[{"m.birthyear":1970,"m.name":"Christopher Nolan"},{"m.birthyear":1939,"m.name":"Corin Redgrave"},{"m.birthyear":1939,"m.name":"Corin Redgrave"},{"m.birthyear":1952,"m.name":"Liam Neeson"},{"m.birthyear":1952,"m.name":"Liam Neeson"}] +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN m.birthyear, m.name ORDER BY m.birthyear desc LIMIT 5; +[{"m.birthyear":1970,"m.name":"Christopher Nolan"},{"m.birthyear":1963,"m.name":"Natasha Richardson"},{"m.birthyear":1952,"m.name":"Liam Neeson"},{"m.birthyear":1952,"m.name":"Liam Neeson"},{"m.birthyear":1939,"m.name":"Corin Redgrave"}] diff --git a/test/resource/unit_test/topn/cypher/topn.test b/test/resource/unit_test/topn/cypher/topn.test new file mode 100644 index 0000000000..cf717e16a6 --- /dev/null +++ b/test/resource/unit_test/topn/cypher/topn.test @@ -0,0 +1,7 @@ +MATCH (a:Person {name:'Lindsay Lohan'}), (b:Film {title:'The Parent Trap'}) CREATE (a)-[r:DIRECTED]->(b); +match (v1:Film) return v1.title order by v1.title limit 3; +match (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,v2.name as cnt order by cnt desc limit 3; +match (:Person {name:'Vanessa Redgrave'})<-[:HAS_CHILD]-(p)-[:ACTED_IN*0..]->(m) return p.name,m order by p.name limit 3; +MATCH (n) RETURN n.name AS name ORDER BY name LIMIT 10; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN m.birthyear, m.name ORDER BY m.name LIMIT 5; +MATCH (n:Person {name:'Vanessa Redgrave'})-[*2]-(m:Person) RETURN m.birthyear, m.name ORDER BY m.birthyear desc LIMIT 5; diff --git a/test/resource/unit_test/undefined_var/cypher/undefined_var.result b/test/resource/unit_test/undefined_var/cypher/undefined_var.result new file mode 100644 index 0000000000..28811c5b54 --- /dev/null +++ b/test/resource/unit_test/undefined_var/cypher/undefined_var.result @@ -0,0 +1,32 @@ +MATCH (n:Person) RETURN q; +[CypherException] CypherException: Unknown variable: q +MATCH (n:Person) RETURN n.name + q.name; +[CypherException] CypherException: Unknown variable: q +MATCH (n:Person) WITH q as m RETURN m; +[InputError] Variable `q` not defined +MATCH (n:Person) WITH k RETURN n; +[InputError] Variable `k` not defined +UNWIND k as n RETURN n; +[InputError] Variable `k` not defined +MATCH (n:Person) WHERE n.name = k RETURN n; +[CypherException] CypherException: Unknown variable: k +MATCH (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by number; +[InputError] Variable `number` not defined +WITH [1,2,3] AS k RETURN [x in k | x + y] AS result; +[InputError] Variable `y` not defined +REMOVE a.name; +[InputError] Variable `a` not defined +SET a :MyLabel; +[InputError] Variable `a` not defined +MATCH (n:Person {name:'D'}),(m:Person {name:'X'}) SET z=m; +[InputError] Variable `z` not defined +MATCH (n:Person {name:'D'}),(m:Person {name:'X'}) SET n=z; +[InputError] Variable `z` not defined +MATCH (n:Person {name:'X'}) SET z.name = "Y"; +[InputError] Variable `z` not defined +MATCH(n:Person {name: 'D'}) DELETE k; +[InputError] Variable `k` not defined +MATCH(n)-[r:REL]-(m) DELETE k; +[InputError] Variable `k` not defined +MATCH (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) WITH v1, count(*) AS edge_num WHERE non_edge > 1 RETURN v1,edge_num; +[InputError] Variable `non_edge` not defined diff --git a/test/resource/unit_test/undefined_var/cypher/undefined_var.test b/test/resource/unit_test/undefined_var/cypher/undefined_var.test new file mode 100644 index 0000000000..d24fba38c5 --- /dev/null +++ b/test/resource/unit_test/undefined_var/cypher/undefined_var.test @@ -0,0 +1,16 @@ +MATCH (n:Person) RETURN q; +MATCH (n:Person) RETURN n.name + q.name; +MATCH (n:Person) WITH q as m RETURN m; +MATCH (n:Person) WITH k RETURN n; +UNWIND k as n RETURN n; +MATCH (n:Person) WHERE n.name = k RETURN n; +MATCH (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) return v1.title,count(distinct v2) as cnt order by number; +WITH [1,2,3] AS k RETURN [x in k | x + y] AS result; +REMOVE a.name; +SET a :MyLabel; +MATCH (n:Person {name:'D'}),(m:Person {name:'X'}) SET z=m; +MATCH (n:Person {name:'D'}),(m:Person {name:'X'}) SET n=z; +MATCH (n:Person {name:'X'}) SET z.name = "Y"; +MATCH(n:Person {name: 'D'}) DELETE k; +MATCH(n)-[r:REL]-(m) DELETE k; +MATCH (v1:Film)<-[:ACTED_IN|DIRECTED]-(v2:Person) WITH v1, count(*) AS edge_num WHERE non_edge > 1 RETURN v1,edge_num; diff --git a/test/resource/unit_test/union/cypher/union.result b/test/resource/unit_test/union/cypher/union.result new file mode 100644 index 0000000000..ce33da0309 --- /dev/null +++ b/test/resource/unit_test/union/cypher/union.result @@ -0,0 +1,6 @@ +MATCH (n:Person)-[:BORN_IN]->(:City {name:'London'}) RETURN n.name UNION MATCH (n:Person)-[:ACTED_IN]->(:Film {title:'The Parent Trap'}) RETURN n.name; +[{"n.name":"Christopher Nolan"},{"n.name":"Natasha Richardson"},{"n.name":"Vanessa Redgrave"},{"n.name":"Dennis Quaid"},{"n.name":"Lindsay Lohan"},{"n.name":"Natasha Richardson"}] +MATCH (n:Person) RETURN n.name AS name UNION MATCH (m:Film) RETURN m.title AS name; +[{"name":"Christopher Nolan"},{"name":"Corin Redgrave"},{"name":"Dennis Quaid"},{"name":"Jemma Redgrave"},{"name":"John Williams"},{"name":"Liam Neeson"},{"name":"Lindsay Lohan"},{"name":"Michael Redgrave"},{"name":"Natasha Richardson"},{"name":"Rachel Kempson"},{"name":"Richard Harris"},{"name":"Roy Redgrave"},{"name":"Vanessa Redgrave"},{"name":"Batman Begins"},{"name":"Camelot"},{"name":"Goodbye, Mr. Chips"},{"name":"Harry Potter and the Sorcerer's Stone"},{"name":"The Parent Trap"}] +MATCH (n:Person)-[:BORN_IN]->(:City {name:'London'}) RETURN n.name UNION MATCH (n:Person)-[:ACTED_IN]->(:Film {title:'The Parent Trap'}) RETURN n.age; +[CypherException] CypherException: All sub queries in an UNION must have the same column names. diff --git a/test/resource/unit_test/union/cypher/union.test b/test/resource/unit_test/union/cypher/union.test new file mode 100644 index 0000000000..81be696f8a --- /dev/null +++ b/test/resource/unit_test/union/cypher/union.test @@ -0,0 +1,3 @@ +MATCH (n:Person)-[:BORN_IN]->(:City {name:'London'}) RETURN n.name UNION MATCH (n:Person)-[:ACTED_IN]->(:Film {title:'The Parent Trap'}) RETURN n.name; +MATCH (n:Person) RETURN n.name AS name UNION MATCH (m:Film) RETURN m.title AS name; +MATCH (n:Person)-[:BORN_IN]->(:City {name:'London'}) RETURN n.name UNION MATCH (n:Person)-[:ACTED_IN]->(:Film {title:'The Parent Trap'}) RETURN n.age; \ No newline at end of file diff --git a/test/resource/unit_test/uniqueness/cypher/uniqueness.result b/test/resource/unit_test/uniqueness/cypher/uniqueness.result new file mode 100644 index 0000000000..cd95820f2c --- /dev/null +++ b/test/resource/unit_test/uniqueness/cypher/uniqueness.result @@ -0,0 +1,34 @@ +MATCH (n1:Person {name:'Liam Neeson'})-->(n2)-->(n3)-->(n4) RETURN n4.title; +[{"n4.title":"Batman Begins"}] +MATCH (n1:Person {name:'Liam Neeson'})<--(n2)<--(n3)<--(n4) RETURN n4; +[{"n4":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n4":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +MATCH (n1:Person {name:'Liam Neeson'})-[*3]->(n2) RETURN n2; +[{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}}] +MATCH (n1:Person {name:'Liam Neeson'})-[*..]->(n2) RETURN n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n2":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}}] +MATCH (n1:Person {name:'Liam Neeson'})-[*2..3]->(n2) RETURN n2; +[{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n2":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}}] +MATCH (n1:Person {name:'Liam Neeson'})-[:MARRIED*..]->(n2) RETURN n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +MATCH (n1:Person {name:'Liam Neeson'})-[:MARRIED|ACTED_IN*..]->(n2) RETURN n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}}] +MATCH (n1:Person {name:'Liam Neeson'})-[:MARRIED|ACTED_IN*2..]->(n2) RETURN n2; +[{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n2":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}}] +MATCH (n1:Person {name:'Michael Redgrave'})-[*3]->(n2) RETURN n2; +[{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n2":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n2":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"n2":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n2":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[*2]-(n2) RETURN n2; +[{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[*4]-(n2) RETURN n2; +[{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[*..]-(n2) RETURN n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[*..]-(n2) RETURN DISTINCT n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED*..]-(n2) RETURN n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED|HAS_CHILD*..]-(n2) RETURN n2; +[{"n2":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED|HAS_CHILD*2..4]-(n2) RETURN n2; +[{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}}] +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED|HAS_CHILD*2..4]-(n2) RETURN DISTINCT n2; +[{"n2":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n2":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n2":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] diff --git a/test/resource/unit_test/uniqueness/cypher/uniqueness.test b/test/resource/unit_test/uniqueness/cypher/uniqueness.test new file mode 100644 index 0000000000..fd63670624 --- /dev/null +++ b/test/resource/unit_test/uniqueness/cypher/uniqueness.test @@ -0,0 +1,17 @@ +MATCH (n1:Person {name:'Liam Neeson'})-->(n2)-->(n3)-->(n4) RETURN n4.title; +MATCH (n1:Person {name:'Liam Neeson'})<--(n2)<--(n3)<--(n4) RETURN n4; +MATCH (n1:Person {name:'Liam Neeson'})-[*3]->(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})-[*..]->(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})-[*2..3]->(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})-[:MARRIED*..]->(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})-[:MARRIED|ACTED_IN*..]->(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})-[:MARRIED|ACTED_IN*2..]->(n2) RETURN n2; +MATCH (n1:Person {name:'Michael Redgrave'})-[*3]->(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[*2]-(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[*4]-(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[*..]-(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[*..]-(n2) RETURN DISTINCT n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED*..]-(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED|HAS_CHILD*..]-(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED|HAS_CHILD*2..4]-(n2) RETURN n2; +MATCH (n1:Person {name:'Liam Neeson'})<-[:MARRIED|HAS_CHILD*2..4]-(n2) RETURN DISTINCT n2; \ No newline at end of file diff --git a/test/resource/unit_test/unwind/cypher/unwind.result b/test/resource/unit_test/unwind/cypher/unwind.result new file mode 100644 index 0000000000..8e5cb15232 --- /dev/null +++ b/test/resource/unit_test/unwind/cypher/unwind.result @@ -0,0 +1,63 @@ +UNWIND [1, 2, 3] AS x RETURN x; +[{"x":1},{"x":2},{"x":3}] +WITH [1, 1, 2, 2] AS coll UNWIND coll AS x RETURN x; +[{"x":1},{"x":1},{"x":2},{"x":2}] +UNWIND $personIds AS personId RETURN personId; +[{"personId":"Liam Neeson"},{"personId":"Dennis Quaid"},{"personId":"Roy Redgrave"}] +UNWIND $personIds AS personId MATCH (n:Person {name:personId}) RETURN n; +[{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +UNWIND [] AS empty RETURN empty, 'literal_that_is_not_returned'; +[] +UNWIND NULL AS x RETURN x, 'some_literal'; +[] +UNWIND [1,2] AS x MATCH (n {name:'Houston'}) RETURN x,n; +[{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":1},{"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":2}] +UNWIND [1,2] AS x MATCH (n {name:'Houston'}),(m:Film) RETURN x,n,m; +[{"m":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":1},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":1},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":1},{"m":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":1},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":1},{"m":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":2},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":2},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":2},{"m":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":2},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":2}] +UNWIND ['Paris','Houston'] AS x MATCH (n {name:x}),(m:Film) RETURN x,n,m; +[{"m":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":"Houston"},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":"Houston"},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":"Houston"},{"m":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":"Houston"},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n":{"identity":15,"label":"City","properties":{"name":"Houston"}},"x":"Houston"}] +MATCH (c {name:'Houston'}) WITH c MATCH (c)<-[r]-(p) RETURN p; +[{"p":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}}] +MATCH (c {name:'Houston'}) WITH c MATCH (p)-[r]->(c) RETURN p; +[{"p":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}}] +MATCH (a {name:'Liam Neeson'}) WITH a,'London' AS cid MATCH (c {name:cid}) RETURN a,c; +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"c":{"identity":14,"label":"City","properties":{"name":"London"}}}] +MATCH (a {name:'Liam Neeson'}) WITH a,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid}) RETURN a,count(c); +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"count(c)":2}] +MATCH (a {name:'Liam Neeson'}),(b {name:'Dennis Quaid'}) WITH a,b,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid}) RETURN a,b,count(c); +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"count(c)":2}] +MATCH (a {name:'Dennis Quaid'}) WITH a,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid})<-[]-(a) RETURN a,count(c); +[{"a":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"count(c)":1}] +MATCH (a {name:'Liam Neeson'}) WITH a,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid})<-[]-()-[:MARRIED]->(a) RETURN a,count(c); +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"count(c)":1}] +MATCH (c {name:'Houston'}) WITH c MATCH (p:Person {name:'Liam Neeson'}) CREATE (c)-[:HAS_CHILD]->(p); +[{"":"created 0 vertices, created 1 edges."}] +MATCH (c {name:'Houston'}) WITH c UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (c)-[:HAS_CHILD]->(q); +[{"":"created 0 vertices, created 3 edges."}] +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer1', birthyear:2002})-[r:BORN_IN]->(c) RETURN p,r,c; +[{"c":{"identity":15,"label":"City","properties":{"name":"Houston"}},"p":{"identity":21,"label":"Person","properties":{"birthyear":2002,"name":"passer1"}},"r":{"dst":15,"forward":false,"identity":0,"label":"BORN_IN","label_id":2,"properties":{"reg_time":null,"weight":null},"src":21,"temporal_id":0}}] +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer2', birthyear:2002})-[r:BORN_IN]->(c) WITH p +UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (p)-[:HAS_CHILD]->(q); +[{"":"created 1 vertices, created 4 edges."}] +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer3', birthyear:2002})-[r:BORN_IN]->(c) WITH p +UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (p)-[:HAS_CHILD]->(q) WITH p +UNWIND ['Liam Neeson'] AS sId MATCH (s:Person {name:sId}) CREATE (p)-[:DIRECTED]->(s) /* 1,7 */; +[{"":"created 1 vertices, created 7 edges."}] +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer4', birthyear:2002})-[r:BORN_IN]->(c) WITH p +UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (p)-[:HAS_CHILD]->(q) WITH p +UNWIND [] AS sId MATCH (s:Person {name:sId}) CREATE (p)-[:DIRECTED]->(s) /* 1,4 */; +[{"":"created 1 vertices, created 4 edges."}] +WITH [1, 1, 2, 2] AS coll UNWIND coll AS x WITH x RETURN collect(x); +[{"collect(x)":[1,1,2,2]}] +WITH [1, 1, 2, 2] AS coll UNWIND coll AS x WITH x RETURN collect(DISTINCT x); +[{"collect(DISTINCT x)":[1,2]}] +CREATE (:City {name:'Shanghai'}), (:City {name:'Zhongshan'}), (:Person {name:'Zhongshan'}); +[{"":"created 3 vertices, created 0 edges."}] +UNWIND ['Zhongshan'] AS x WITH x MATCH (a {name:x}) RETURN a,a.name; +[{"a":{"identity":27,"label":"Person","properties":{"birthyear":null,"name":"Zhongshan"}},"a.name":"Zhongshan"},{"a":{"identity":26,"label":"City","properties":{"name":"Zhongshan"}},"a.name":"Zhongshan"}] +UNWIND ['Zhongshan', 'Shanghai'] AS x WITH x MATCH (a {name:x}) RETURN a,a.name; +[{"a":{"identity":27,"label":"Person","properties":{"birthyear":null,"name":"Zhongshan"}},"a.name":"Zhongshan"},{"a":{"identity":26,"label":"City","properties":{"name":"Zhongshan"}},"a.name":"Zhongshan"},{"a":{"identity":25,"label":"City","properties":{"name":"Shanghai"}},"a.name":"Shanghai"}] diff --git a/test/resource/unit_test/unwind/cypher/unwind.test b/test/resource/unit_test/unwind/cypher/unwind.test new file mode 100644 index 0000000000..0c508b58d1 --- /dev/null +++ b/test/resource/unit_test/unwind/cypher/unwind.test @@ -0,0 +1,36 @@ +UNWIND [1, 2, 3] AS x RETURN x; +WITH [1, 1, 2, 2] AS coll UNWIND coll AS x RETURN x; +UNWIND $personIds AS personId RETURN personId; +UNWIND $personIds AS personId MATCH (n:Person {name:personId}) RETURN n; +UNWIND [] AS empty RETURN empty, 'literal_that_is_not_returned'; +UNWIND NULL AS x RETURN x, 'some_literal'; +UNWIND [1,2] AS x MATCH (n {name:'Houston'}) RETURN x,n; +UNWIND [1,2] AS x MATCH (n {name:'Houston'}),(m:Film) RETURN x,n,m; +UNWIND ['Paris','Houston'] AS x MATCH (n {name:x}),(m:Film) RETURN x,n,m; +MATCH (c {name:'Houston'}) WITH c MATCH (c)<-[r]-(p) RETURN p; +MATCH (c {name:'Houston'}) WITH c MATCH (p)-[r]->(c) RETURN p; +MATCH (a {name:'Liam Neeson'}) WITH a,'London' AS cid MATCH (c {name:cid}) RETURN a,c; +MATCH (a {name:'Liam Neeson'}) WITH a,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid}) RETURN a,count(c); +MATCH (a {name:'Liam Neeson'}),(b {name:'Dennis Quaid'}) WITH a,b,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid}) RETURN a,b,count(c); +MATCH (a {name:'Dennis Quaid'}) WITH a,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid})<-[]-(a) RETURN a,count(c); +MATCH (a {name:'Liam Neeson'}) WITH a,['London','Houston'] AS cids +UNWIND cids AS cid MATCH (c {name:cid})<-[]-()-[:MARRIED]->(a) RETURN a,count(c); +MATCH (c {name:'Houston'}) WITH c MATCH (p:Person {name:'Liam Neeson'}) CREATE (c)-[:HAS_CHILD]->(p); +MATCH (c {name:'Houston'}) WITH c UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (c)-[:HAS_CHILD]->(q); +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer1', birthyear:2002})-[r:BORN_IN]->(c) RETURN p,r,c; +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer2', birthyear:2002})-[r:BORN_IN]->(c) WITH p +UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (p)-[:HAS_CHILD]->(q); +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer3', birthyear:2002})-[r:BORN_IN]->(c) WITH p +UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (p)-[:HAS_CHILD]->(q) WITH p +UNWIND ['Liam Neeson'] AS sId MATCH (s:Person {name:sId}) CREATE (p)-[:DIRECTED]->(s) /* 1,7 */; +MATCH (c {name:'Houston'}) CREATE (p:Person {name:'passer4', birthyear:2002})-[r:BORN_IN]->(c) WITH p +UNWIND $personIds AS pId MATCH (q:Person {name:pId}) CREATE (p)-[:HAS_CHILD]->(q) WITH p +UNWIND [] AS sId MATCH (s:Person {name:sId}) CREATE (p)-[:DIRECTED]->(s) /* 1,4 */; +WITH [1, 1, 2, 2] AS coll UNWIND coll AS x WITH x RETURN collect(x); +WITH [1, 1, 2, 2] AS coll UNWIND coll AS x WITH x RETURN collect(DISTINCT x); +CREATE (:City {name:'Shanghai'}), (:City {name:'Zhongshan'}), (:Person {name:'Zhongshan'}); +UNWIND ['Zhongshan'] AS x WITH x MATCH (a {name:x}) RETURN a,a.name; +UNWIND ['Zhongshan', 'Shanghai'] AS x WITH x MATCH (a {name:x}) RETURN a,a.name; \ No newline at end of file diff --git a/test/resource/unit_test/var_len_edge/cypher/var_len_edge.result b/test/resource/unit_test/var_len_edge/cypher/var_len_edge.result new file mode 100644 index 0000000000..3b91439053 --- /dev/null +++ b/test/resource/unit_test/var_len_edge/cypher/var_len_edge.result @@ -0,0 +1,76 @@ +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]->(n)-[:ACTED_IN]->(m) RETURN n,m; +[{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1..5]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1..2]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*2..5]->(n) RETURN n; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1..]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*2..]->(n) RETURN n; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..2]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..3]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1]->(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*2]->(n) RETURN n; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[*..]->(n) RETURN DISTINCT n,n.name,n.title; +[{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n.name":"Natasha Richardson","n.title":null},{"n":{"identity":14,"label":"City","properties":{"name":"London"}},"n.name":"London","n.title":null},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.name":null,"n.title":"Camelot"},{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n.name":"Liam Neeson","n.title":null},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.name":null,"n.title":"The Parent Trap"},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n.name":null,"n.title":"Batman Begins"}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[*3]->(n) RETURN n; +[{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[*2..]->(n) RETURN n; +[{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[]->()-[*0]->(m) RETURN m; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[]->()-[*0..1]->(m) RETURN DISTINCT m; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"m":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +MATCH (mic:Person {name:'Michael Redgrave'})-[]->()-[*0..1]->(m) RETURN DISTINCT m; +[{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"m":{"identity":14,"label":"City","properties":{"name":"London"}}},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}},{"m":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"m":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"m":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}}] +MATCH (jem:Person {name:'Jemma Redgrave'})<-[:HAS_CHILD*..]-(a) RETURN a; +[{"a":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"a":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"a":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"a":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (jem:Person {name:'Jemma Redgrave'})<-[:HAS_CHILD*..]-(a)-[:ACTED_IN*..]->(m) RETURN a,m; +[{"a":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD|MARRIED*..]->(n) RETURN DISTINCT n.name; +[{"n.name":"Michael Redgrave"},{"n.name":"Vanessa Redgrave"},{"n.name":"Corin Redgrave"},{"n.name":"Rachel Kempson"},{"n.name":"Natasha Richardson"},{"n.name":"Jemma Redgrave"},{"n.name":"Liam Neeson"}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD|MARRIED*1..2]->(n) RETURN DISTINCT n.name; +[{"n.name":"Michael Redgrave"},{"n.name":"Vanessa Redgrave"},{"n.name":"Corin Redgrave"},{"n.name":"Rachel Kempson"}] +MATCH (liam:Person {name:'Liam Neeson'})<-[:HAS_CHILD|MARRIED*1..3]-(a) RETURN DISTINCT a.name; +[{"a.name":"Natasha Richardson"},{"a.name":"Vanessa Redgrave"},{"a.name":"Liam Neeson"},{"a.name":"Rachel Kempson"},{"a.name":"Michael Redgrave"}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]-(n) RETURN n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]-(n) RETURN DISTINCT n; +[{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}}] +MATCH (jem:Person {name:'Jemma Redgrave'})-[:HAS_CHILD*..]-(a) RETURN a; +[{"a":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"a":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"a":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"a":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"a":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"a":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"a":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"a":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"a":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"a":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"a":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"a":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"a":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}}] +MATCH (jem:Person {name:'Jemma Redgrave'})-[:HAS_CHILD*..]-(a) RETURN DISTINCT a; +[{"a":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"a":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"a":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"a":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"a":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"a":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*..]-(n) RETURN n; +[{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*..]-(n) RETURN DISTINCT n; +[{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*1..2]-(n) RETURN n; +[{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*2]-(n) RETURN n; +[{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}}] +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*2..]-(n) RETURN n; +[{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":3,"label":"Person","properties":{"birthyear":1939,"name":"Corin Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"n":{"identity":9,"label":"Person","properties":{"birthyear":1965,"name":"Jemma Redgrave"}}},{"n":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":10,"label":"Person","properties":{"birthyear":1873,"name":"Roy Redgrave"}}},{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}},{"n":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}}}] +MATCH (n:Person)-[:BORN_IN*0..]->(m) RETURN n.name,m.name; +[{"m.name":"Christopher Nolan","n.name":"Christopher Nolan"},{"m.name":"London","n.name":"Christopher Nolan"},{"m.name":"Corin Redgrave","n.name":"Corin Redgrave"},{"m.name":"Dennis Quaid","n.name":"Dennis Quaid"},{"m.name":"Houston","n.name":"Dennis Quaid"},{"m.name":"Jemma Redgrave","n.name":"Jemma Redgrave"},{"m.name":"John Williams","n.name":"John Williams"},{"m.name":"New York","n.name":"John Williams"},{"m.name":"Liam Neeson","n.name":"Liam Neeson"},{"m.name":"Lindsay Lohan","n.name":"Lindsay Lohan"},{"m.name":"New York","n.name":"Lindsay Lohan"},{"m.name":"Michael Redgrave","n.name":"Michael Redgrave"},{"m.name":"Natasha Richardson","n.name":"Natasha Richardson"},{"m.name":"London","n.name":"Natasha Richardson"},{"m.name":"Rachel Kempson","n.name":"Rachel Kempson"},{"m.name":"Richard Harris","n.name":"Richard Harris"},{"m.name":"Roy Redgrave","n.name":"Roy Redgrave"},{"m.name":"Vanessa Redgrave","n.name":"Vanessa Redgrave"},{"m.name":"London","n.name":"Vanessa Redgrave"}] +MATCH (n:Person)-[:BORN_IN*0..]->(m:City) RETURN n.name,m.name; +[{"m.name":"London","n.name":"Christopher Nolan"},{"m.name":"Houston","n.name":"Dennis Quaid"},{"m.name":"New York","n.name":"John Williams"},{"m.name":"New York","n.name":"Lindsay Lohan"},{"m.name":"London","n.name":"Natasha Richardson"},{"m.name":"London","n.name":"Vanessa Redgrave"}] +MATCH (n:Person)-[:BORN_IN*0..]->(m:Person) RETURN n.name,m.name; +[{"m.name":"Christopher Nolan","n.name":"Christopher Nolan"},{"m.name":"Corin Redgrave","n.name":"Corin Redgrave"},{"m.name":"Dennis Quaid","n.name":"Dennis Quaid"},{"m.name":"Jemma Redgrave","n.name":"Jemma Redgrave"},{"m.name":"John Williams","n.name":"John Williams"},{"m.name":"Liam Neeson","n.name":"Liam Neeson"},{"m.name":"Lindsay Lohan","n.name":"Lindsay Lohan"},{"m.name":"Michael Redgrave","n.name":"Michael Redgrave"},{"m.name":"Natasha Richardson","n.name":"Natasha Richardson"},{"m.name":"Rachel Kempson","n.name":"Rachel Kempson"},{"m.name":"Richard Harris","n.name":"Richard Harris"},{"m.name":"Roy Redgrave","n.name":"Roy Redgrave"},{"m.name":"Vanessa Redgrave","n.name":"Vanessa Redgrave"}] +MATCH (n:Film)<-[:ACTED_IN*0..]-(m) RETURN n.title,n,m; +[{"m":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n.title":"Batman Begins"},{"m":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n.title":"Batman Begins"},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"},{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"},{"m":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n.title":"Goodbye, Mr. Chips"},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n.title":"Goodbye, Mr. Chips"},{"m":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n.title":"Harry Potter and the Sorcerer's Stone"},{"m":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n.title":"Harry Potter and the Sorcerer's Stone"},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"},{"m":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"},{"m":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"}] +MATCH (n:Film)<-[:ACTED_IN*0..]-(m:Person) RETURN n.title,n,m; +[{"m":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n.title":"Batman Begins"},{"m":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"},{"m":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"},{"m":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n.title":"Goodbye, Mr. Chips"},{"m":{"identity":6,"label":"Person","properties":{"birthyear":1930,"name":"Richard Harris"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n.title":"Harry Potter and the Sorcerer's Stone"},{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"},{"m":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"},{"m":{"identity":8,"label":"Person","properties":{"birthyear":1986,"name":"Lindsay Lohan"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"}] +MATCH (n:Film)<-[:ACTED_IN*0..]-(m:Film) RETURN n.title,n,m; +[{"m":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n.title":"Batman Begins"},{"m":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"n.title":"Camelot"},{"m":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"n.title":"Goodbye, Mr. Chips"},{"m":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"n.title":"Harry Potter and the Sorcerer's Stone"},{"m":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"n.title":"The Parent Trap"}] +MATCH (n:Film)<-[:ACTED_IN*0..]-(m:City) RETURN n.title,n,m; +[] diff --git a/test/resource/unit_test/var_len_edge/cypher/var_len_edge.test b/test/resource/unit_test/var_len_edge/cypher/var_len_edge.test new file mode 100644 index 0000000000..005b5a3e45 --- /dev/null +++ b/test/resource/unit_test/var_len_edge/cypher/var_len_edge.test @@ -0,0 +1,38 @@ +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]->(n)-[:ACTED_IN]->(m) RETURN n,m; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1..5]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1..2]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*2..5]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1..]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*2..]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..2]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..3]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*1]->(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*2]->(n) RETURN n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[*..]->(n) RETURN DISTINCT n,n.name,n.title; +MATCH (van:Person {name:'Vanessa Redgrave'})-[*3]->(n) RETURN n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[*2..]->(n) RETURN n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[]->()-[*0]->(m) RETURN m; +MATCH (van:Person {name:'Vanessa Redgrave'})-[]->()-[*0..1]->(m) RETURN DISTINCT m; +MATCH (mic:Person {name:'Michael Redgrave'})-[]->()-[*0..1]->(m) RETURN DISTINCT m; +MATCH (jem:Person {name:'Jemma Redgrave'})<-[:HAS_CHILD*..]-(a) RETURN a; +MATCH (jem:Person {name:'Jemma Redgrave'})<-[:HAS_CHILD*..]-(a)-[:ACTED_IN*..]->(m) RETURN a,m; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD|MARRIED*..]->(n) RETURN DISTINCT n.name; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD|MARRIED*1..2]->(n) RETURN DISTINCT n.name; +MATCH (liam:Person {name:'Liam Neeson'})<-[:HAS_CHILD|MARRIED*1..3]-(a) RETURN DISTINCT a.name; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]-(n) RETURN n; +MATCH (roy:Person {name:'Roy Redgrave'})-[:HAS_CHILD*..]-(n) RETURN DISTINCT n; +MATCH (jem:Person {name:'Jemma Redgrave'})-[:HAS_CHILD*..]-(a) RETURN a; +MATCH (jem:Person {name:'Jemma Redgrave'})-[:HAS_CHILD*..]-(a) RETURN DISTINCT a; +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*..]-(n) RETURN n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*..]-(n) RETURN DISTINCT n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*1..2]-(n) RETURN n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*2]-(n) RETURN n; +MATCH (van:Person {name:'Vanessa Redgrave'})-[:HAS_CHILD*2..]-(n) RETURN n; +MATCH (n:Person)-[:BORN_IN*0..]->(m) RETURN n.name,m.name; +MATCH (n:Person)-[:BORN_IN*0..]->(m:City) RETURN n.name,m.name; +MATCH (n:Person)-[:BORN_IN*0..]->(m:Person) RETURN n.name,m.name; +MATCH (n:Film)<-[:ACTED_IN*0..]-(m) RETURN n.title,n,m; +MATCH (n:Film)<-[:ACTED_IN*0..]-(m:Person) RETURN n.title,n,m; +MATCH (n:Film)<-[:ACTED_IN*0..]-(m:Film) RETURN n.title,n,m; +MATCH (n:Film)<-[:ACTED_IN*0..]-(m:City) RETURN n.title,n,m; \ No newline at end of file diff --git a/test/resource/unit_test/with/cypher/with.result b/test/resource/unit_test/with/cypher/with.result new file mode 100644 index 0000000000..13f5283907 --- /dev/null +++ b/test/resource/unit_test/with/cypher/with.result @@ -0,0 +1,86 @@ +match (n {name:'Liam Neeson'}) with n as n1 match (n {name:'John Williams'}) return n,n1; +[{"n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"n1":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +match (n {name:'Liam Neeson'}) with n as n1 match (n {name:'Dennis Quaid'}) with n as n2, n1 match (n {name:'John Williams'}) return n,n2,n1; +[{"n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"n1":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n2":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}}] +match (n {name:'Liam Neeson'}) with n as n1 match (n {name:'Dennis Quaid'}) with n as n2, n1.name as n1name match (n {name:'John Williams'}) return n,n2,n1name; +[{"n":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"n1name":"Liam Neeson","n2":{"identity":7,"label":"Person","properties":{"birthyear":1954,"name":"Dennis Quaid"}}}] +match (n {name:'Liam Neeson'}) with n return n; +[{"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +match (n {name:'Liam Neeson'}) with n match (n)-->(m) return n,m; +[{"m":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"m":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +#match (n {name:'London'}) with n optional match (n)-->(m) return n,m; +match (a {name:'Liam Neeson'})-[r]->(b) with b match (b)-[]->(c) return c; +[{"c":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"c":{"identity":14,"label":"City","properties":{"name":"London"}}},{"c":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}}] +match (a {name:'Liam Neeson'}),(b {name:'London'}) with a, b match (c:Film) return a,b,c; +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}},"c":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}}},{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}},"c":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}}},{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}},"c":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}}},{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}},"c":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}},{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":14,"label":"City","properties":{"name":"London"}},"c":{"identity":20,"label":"Film","properties":{"title":"Camelot"}}}] +match (n {name:'Liam Neeson'}) with n match (n) return n.name; +[{"n.name":"Liam Neeson"}] +match (a {name:'Liam Neeson'}), (b {name:'London'}) with a, b match (a), (b) return a.name, b.name; +[{"a.name":"Liam Neeson","b.name":"London"}] +MATCH (a {name:'Liam Neeson'})-[r]->(b) RETURN a,count(b) AS out_num; +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"out_num":2}] +MATCH (a {name:'Liam Neeson'})-[r]->(b) WITH a,count(b) AS out_num MATCH (a)<-[]-(c) RETURN count(c) AS in_num,out_num; +[{"in_num":1,"out_num":2}] +match (a {name:'Liam Neeson'})-[r]->(b) with a,b match (b)-[]->(c) return a,b,c; +[{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"c":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"c":{"identity":14,"label":"City","properties":{"name":"London"}}},{"a":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"b":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"c":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}}}] +#match (n {name:'Liam Neeson'}),(m {name:'Natasha Richardson'}),(n)-[r]->(m) return r,type(r); +match (n {name:'Liam Neeson'}),(m {name:'Natasha Richardson'}) with n,m match (n)-[r]->(m) return r,type(r); +[{"r":{"dst":5,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":4,"temporal_id":0},"type(r)":"MARRIED"}] +match (n {name:'Liam Neeson'}),(m {name:'Liam Neeson'}) with n,m optional match (n)-[r]->(m) return r,type(r); +[{"r":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0},"type(r)":null}] +match (n {name:'Liam Neeson'})-[r]->(m) with r return r,type(r); +[{"r":{"dst":5,"forward":false,"identity":0,"label":"MARRIED","label_id":1,"src":4,"temporal_id":0},"type(r)":"MARRIED"},{"r":{"dst":17,"forward":false,"identity":0,"label":"ACTED_IN","label_id":5,"properties":{"charactername":"Henri Ducard"},"src":4,"temporal_id":0},"type(r)":"ACTED_IN"}] +match (n:City) with count (n) as num_city match (n:Film) return count(n) as num_film, num_city; +[{"num_city":3,"num_film":5}] +match (n:Person {name:'Vanessa Redgrave'})-->(m) with m as m1 match (n:Person {name:'Vanessa Redgrave'})<--(m) return m as m2, m1; +[{"m1":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"m2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m1":{"identity":5,"label":"Person","properties":{"birthyear":1963,"name":"Natasha Richardson"}},"m2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m1":{"identity":14,"label":"City","properties":{"name":"London"}},"m2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m1":{"identity":14,"label":"City","properties":{"name":"London"}},"m2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}},{"m1":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"m2":{"identity":0,"label":"Person","properties":{"birthyear":1910,"name":"Rachel Kempson"}}},{"m1":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"m2":{"identity":1,"label":"Person","properties":{"birthyear":1908,"name":"Michael Redgrave"}}}] +match (n:Person {name:'Vanessa Redgrave'})-->(m) with count(m) as c1 match (n:Person {name:'Vanessa Redgrave'})<--(m) return count(m) as c2, c1; +[{"c1":3,"c2":2}] +match (n:Person {name:'Vanessa Redgrave'})-->(m) with count(m) as cm1 match (n:Person {name:'Vanessa Redgrave'})<--(m) with count(m) as cm2, cm1 match (n:Person {name:'Natasha Richardson'})-->(m) return count(m) as cm3, cm2, cm1; +[{"cm1":3,"cm2":2,"cm3":3}] +match (n:Person {name:'Michael Redgrave'})-->(m:Person) where m.birthyear > 1938 with count(m) as p38 match (n:Person {name:'Michael Redgrave'})-->(m:Person) where m.birthyear > 1908 return count(m) as p08,p38 /* 3,1 */; +[{"p08":3,"p38":1}] +WITH 2020 AS x WHERE x > 2020 RETURN x; +[] +MATCH (n:City) WITH 2020 AS x, n.name AS y ORDER BY y WHERE x = 2020 RETURN x,y; +[{"x":2020,"y":"Houston"},{"x":2020,"y":"London"},{"x":2020,"y":"New York"}] +MATCH (n) WITH n WHERE n.name = 'Liam Neeson' MATCH (m {name:'John Williams'}) RETURN n,m; +[{"m":{"identity":11,"label":"Person","properties":{"birthyear":1932,"name":"John Williams"}},"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +MATCH (n:Person {name:'Michael Redgrave'})-->(m:Person) WHERE m.birthyear > 1908 WITH count(m) AS p08 RETURN p08 /* 3 */; +[{"p08":3}] +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH m, count(*) AS edge_num WHERE edge_num > 1.0 RETURN m.name,edge_num; +[{"edge_num":2,"m.name":"Rachel Kempson"}] +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH n, m, count(*) AS edge_num WHERE edge_num > 1.0 OR n.birthyear > 1900 RETURN m.name,edge_num; +[{"edge_num":1,"m.name":"Roy Redgrave"},{"edge_num":2,"m.name":"Rachel Kempson"},{"edge_num":1,"m.name":null},{"edge_num":1,"m.name":"Vanessa Redgrave"},{"edge_num":1,"m.name":"Corin Redgrave"}] +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH m, count(*) AS edge_num WHERE edge_num > 1.0 AND m.birthyear > 1900 RETURN m.name,edge_num; +[{"edge_num":2,"m.name":"Rachel Kempson"}] +MATCH (n:Person {name:'Michael Redgrave'})--(nbr)-->() WITH nbr, count(*) AS foaf WHERE foaf > 1.0 RETURN nbr.name,foaf; +[{"foaf":3,"nbr.name":"Vanessa Redgrave"},{"foaf":5,"nbr.name":"Rachel Kempson"}] +MATCH (n:Person {name:'Michael Redgrave'}) WHERE n.birthyear > 1900 AND n.birthyear < 2000 RETURN n.name; +[{"n.name":"Michael Redgrave"}] +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH m, count(*) AS edge_num WHERE toInteger(edge_num) > 1 RETURN m.name,edge_num; +[{"edge_num":2,"m.name":"Rachel Kempson"}] +MATCH (n:Person {name:'Michael Redgrave'})--(nbr)-->() WITH nbr, count(*) AS foaf WHERE toInteger(foaf) > 1 RETURN nbr.name,foaf; +[{"foaf":3,"nbr.name":"Vanessa Redgrave"},{"foaf":5,"nbr.name":"Rachel Kempson"}] +MATCH (a:City) WITH a MATCH (b:Person {name:'Liam Neeson'}) RETURN a,b; +[{"a":{"identity":15,"label":"City","properties":{"name":"Houston"}},"b":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"a":{"identity":14,"label":"City","properties":{"name":"London"}},"b":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}},{"a":{"identity":13,"label":"City","properties":{"name":"New York"}},"b":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +WITH 'Vanessa Redgrave' AS varName MATCH (n:Film) RETURN n,varName; +[{"n":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"varName":"Vanessa Redgrave"},{"n":{"identity":17,"label":"Film","properties":{"title":"Batman Begins"}},"varName":"Vanessa Redgrave"},{"n":{"identity":18,"label":"Film","properties":{"title":"Harry Potter and the Sorcerer's Stone"}},"varName":"Vanessa Redgrave"},{"n":{"identity":19,"label":"Film","properties":{"title":"The Parent Trap"}},"varName":"Vanessa Redgrave"},{"n":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"varName":"Vanessa Redgrave"}] +WITH 'Vanessa Redgrave' AS varName MATCH (n {name:varName}) RETURN n; +[{"n":{"identity":2,"label":"Person","properties":{"birthyear":1937,"name":"Vanessa Redgrave"}}}] +MATCH (n {birthyear:1952}) WITH n,n.name AS varName MATCH (m {name:varName}) RETURN n,m; +[{"m":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}},"n":{"identity":4,"label":"Person","properties":{"birthyear":1952,"name":"Liam Neeson"}}}] +WITH 1 AS a MATCH (n:City) RETURN DISTINCT a,n; +[{"a":1,"n":{"identity":13,"label":"City","properties":{"name":"New York"}}},{"a":1,"n":{"identity":14,"label":"City","properties":{"name":"London"}}},{"a":1,"n":{"identity":15,"label":"City","properties":{"name":"Houston"}}}] +MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m MATCH (m)-[:ACTED_IN]->(film) RETURN m.name,film; +[{"film":{"identity":20,"label":"Film","properties":{"title":"Camelot"}},"m.name":"Vanessa Redgrave"},{"film":{"identity":16,"label":"Film","properties":{"title":"Goodbye, Mr. Chips"}},"m.name":"Michael Redgrave"}] +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film) RETURN m.name,film; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(coactor) RETURN m.name,film,coactor; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film) WITH m,film RETURN m.name,film; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film) WITH m,film OPTIONAL MATCH (film)<-[:WROTE_MUSIC_FOR]-(musician) RETURN m.name,film,musician; +match (n:Person) where n.name='Michael Redgrave' with n.birthyear as nb match (p)-[:HAS_CHILD]->(c) where p.birthyear=nb return c.name; +[{"c.name":"Vanessa Redgrave"},{"c.name":"Corin Redgrave"}] +#match (n:Person) where n.name='Roy Redgrave' or n.name='Michael Redgrave' with collect(id(n)) as cn match (p:Person) where id(p) in cn return p.name; +#match (n:Person) where n.name='Roy Redgrave' or n.name='Michael Redgrave' with n, collect(id(n)) as cn match (p:Person) where id(p) in cn return p.name; +match (c:Person)-[:HAS_CHILD]->(f:Person) where c.name='Roy Redgrave' with c, f match (m:Person)-[:ACTED_IN]->(film:Film)<-[:WROTE_MUSIC_FOR]-(p:Person) where m.name=f.name return c.name, p.name; +[{"c.name":"Roy Redgrave","p.name":"John Williams"}] diff --git a/test/resource/unit_test/with/cypher/with.test b/test/resource/unit_test/with/cypher/with.test new file mode 100644 index 0000000000..aaafee9b11 --- /dev/null +++ b/test/resource/unit_test/with/cypher/with.test @@ -0,0 +1,47 @@ +match (n {name:'Liam Neeson'}) with n as n1 match (n {name:'John Williams'}) return n,n1; +match (n {name:'Liam Neeson'}) with n as n1 match (n {name:'Dennis Quaid'}) with n as n2, n1 match (n {name:'John Williams'}) return n,n2,n1; +match (n {name:'Liam Neeson'}) with n as n1 match (n {name:'Dennis Quaid'}) with n as n2, n1.name as n1name match (n {name:'John Williams'}) return n,n2,n1name; +match (n {name:'Liam Neeson'}) with n return n; +match (n {name:'Liam Neeson'}) with n match (n)-->(m) return n,m; +#match (n {name:'London'}) with n optional match (n)-->(m) return n,m; +match (a {name:'Liam Neeson'})-[r]->(b) with b match (b)-[]->(c) return c; +match (a {name:'Liam Neeson'}),(b {name:'London'}) with a, b match (c:Film) return a,b,c; +match (n {name:'Liam Neeson'}) with n match (n) return n.name; +match (a {name:'Liam Neeson'}), (b {name:'London'}) with a, b match (a), (b) return a.name, b.name; +MATCH (a {name:'Liam Neeson'})-[r]->(b) RETURN a,count(b) AS out_num; +MATCH (a {name:'Liam Neeson'})-[r]->(b) WITH a,count(b) AS out_num MATCH (a)<-[]-(c) RETURN count(c) AS in_num,out_num; +match (a {name:'Liam Neeson'})-[r]->(b) with a,b match (b)-[]->(c) return a,b,c; +#match (n {name:'Liam Neeson'}),(m {name:'Natasha Richardson'}),(n)-[r]->(m) return r,type(r); +match (n {name:'Liam Neeson'}),(m {name:'Natasha Richardson'}) with n,m match (n)-[r]->(m) return r,type(r); +match (n {name:'Liam Neeson'}),(m {name:'Liam Neeson'}) with n,m optional match (n)-[r]->(m) return r,type(r); +match (n {name:'Liam Neeson'})-[r]->(m) with r return r,type(r); +match (n:City) with count (n) as num_city match (n:Film) return count(n) as num_film, num_city; +match (n:Person {name:'Vanessa Redgrave'})-->(m) with m as m1 match (n:Person {name:'Vanessa Redgrave'})<--(m) return m as m2, m1; +match (n:Person {name:'Vanessa Redgrave'})-->(m) with count(m) as c1 match (n:Person {name:'Vanessa Redgrave'})<--(m) return count(m) as c2, c1; +match (n:Person {name:'Vanessa Redgrave'})-->(m) with count(m) as cm1 match (n:Person {name:'Vanessa Redgrave'})<--(m) with count(m) as cm2, cm1 match (n:Person {name:'Natasha Richardson'})-->(m) return count(m) as cm3, cm2, cm1; +match (n:Person {name:'Michael Redgrave'})-->(m:Person) where m.birthyear > 1938 with count(m) as p38 match (n:Person {name:'Michael Redgrave'})-->(m:Person) where m.birthyear > 1908 return count(m) as p08,p38 /* 3,1 */; +WITH 2020 AS x WHERE x > 2020 RETURN x; +MATCH (n:City) WITH 2020 AS x, n.name AS y ORDER BY y WHERE x = 2020 RETURN x,y; +MATCH (n) WITH n WHERE n.name = 'Liam Neeson' MATCH (m {name:'John Williams'}) RETURN n,m; +MATCH (n:Person {name:'Michael Redgrave'})-->(m:Person) WHERE m.birthyear > 1908 WITH count(m) AS p08 RETURN p08 /* 3 */; +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH m, count(*) AS edge_num WHERE edge_num > 1.0 RETURN m.name,edge_num; +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH n, m, count(*) AS edge_num WHERE edge_num > 1.0 OR n.birthyear > 1900 RETURN m.name,edge_num; +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH m, count(*) AS edge_num WHERE edge_num > 1.0 AND m.birthyear > 1900 RETURN m.name,edge_num; +MATCH (n:Person {name:'Michael Redgrave'})--(nbr)-->() WITH nbr, count(*) AS foaf WHERE foaf > 1.0 RETURN nbr.name,foaf; +MATCH (n:Person {name:'Michael Redgrave'}) WHERE n.birthyear > 1900 AND n.birthyear < 2000 RETURN n.name; +MATCH (n:Person {name:'Michael Redgrave'})--(m) WITH m, count(*) AS edge_num WHERE toInteger(edge_num) > 1 RETURN m.name,edge_num; +MATCH (n:Person {name:'Michael Redgrave'})--(nbr)-->() WITH nbr, count(*) AS foaf WHERE toInteger(foaf) > 1 RETURN nbr.name,foaf; +MATCH (a:City) WITH a MATCH (b:Person {name:'Liam Neeson'}) RETURN a,b; +WITH 'Vanessa Redgrave' AS varName MATCH (n:Film) RETURN n,varName; +WITH 'Vanessa Redgrave' AS varName MATCH (n {name:varName}) RETURN n; +MATCH (n {birthyear:1952}) WITH n,n.name AS varName MATCH (m {name:varName}) RETURN n,m; +WITH 1 AS a MATCH (n:City) RETURN DISTINCT a,n; +MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m MATCH (m)-[:ACTED_IN]->(film) RETURN m.name,film; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film) RETURN m.name,film; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film)<-[:ACTED_IN]-(coactor) RETURN m.name,film,coactor; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film) WITH m,film RETURN m.name,film; +#MATCH (n {name:'Rachel Kempson'})-[]->(m:Person) WITH m OPTIONAL MATCH (m)-[:ACTED_IN]->(film) WITH m,film OPTIONAL MATCH (film)<-[:WROTE_MUSIC_FOR]-(musician) RETURN m.name,film,musician; +match (n:Person) where n.name='Michael Redgrave' with n.birthyear as nb match (p)-[:HAS_CHILD]->(c) where p.birthyear=nb return c.name; +#match (n:Person) where n.name='Roy Redgrave' or n.name='Michael Redgrave' with collect(id(n)) as cn match (p:Person) where id(p) in cn return p.name; +#match (n:Person) where n.name='Roy Redgrave' or n.name='Michael Redgrave' with n, collect(id(n)) as cn match (p:Person) where id(p) in cn return p.name; +match (c:Person)-[:HAS_CHILD]->(f:Person) where c.name='Roy Redgrave' with c, f match (m:Person)-[:ACTED_IN]->(film:Film)<-[:WROTE_MUSIC_FOR]-(p:Person) where m.name=f.name return c.name, p.name; \ No newline at end of file diff --git a/test/test_cypher_v2.cpp b/test/test_cypher_v2.cpp new file mode 100644 index 0000000000..e31152aa27 --- /dev/null +++ b/test/test_cypher_v2.cpp @@ -0,0 +1,567 @@ +/** + * Copyright 2022 AntGroup CO., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + */ + +#include +#include +#include +#include + +#include "./graph_factory.h" +/* Make sure include graph_factory.h BEFORE antlr4-runtime.h. Otherwise causing the following error: + * ‘EOF’ was not declared in this scope. + * For the former (include/butil) uses macro EOF, which is undefined in antlr4. */ +#include "./antlr4-runtime.h" +#include "geax-front-end/ast/AstNode.h" +#include "geax-front-end/ast/AstDumper.h" +#include "geax-front-end/isogql/GQLResolveCtx.h" +#include "geax-front-end/isogql/GQLAstVisitor.h" +#include "geax-front-end/isogql/parser/AntlrGqlParser.h" + +#include "cypher/parser/generated/LcypherLexer.h" +#include "cypher/parser/generated/LcypherParser.h" +#include "cypher/parser/cypher_base_visitor_v2.h" +#include "cypher/parser/cypher_error_listener.h" +#include "cypher/rewriter/GenAnonymousAliasRewriter.h" +#include "fma-common/file_system.h" +#include "db/galaxy.h" +#include "cypher/execution_plan/runtime_context.h" +#include "cypher/execution_plan/execution_plan_v2.h" +#include "lgraph/lgraph_utils.h" +#include "./ut_utils.h" +#include "./ut_config.h" +#include "./ut_types.h" + +using namespace geax::frontend; +using geax::frontend::GEAXErrorCode; + +extern GraphFactory::GRAPH_DATASET_TYPE _ut_graph_dataset_type; +extern lgraph::ut::QUERY_TYPE _ut_query_type; + +static const cypher::PARAM_TAB g_param_tab = { + {"$name", cypher::FieldData(lgraph::FieldData("Lindsay Lohan"))}, + {"$personId", cypher::FieldData(lgraph::FieldData(1))}, + {"$personIds", cypher::FieldData(std::vector{ + lgraph::FieldData("Liam Neeson"), lgraph::FieldData("Dennis Quaid"), + lgraph::FieldData("Roy Redgrave")})}, +}; + +class TestCypherV2 : public TuGraphTest { + private: + std::shared_ptr ctx_; + std::shared_ptr galaxy_; + lgraph::Galaxy::Config gconf_; + inline static const std::string TEST_SUFFIX = ".test"; + inline static const std::string REAL_SUFFIX = ".real"; + inline static const std::string RESULT_SUFFIX = ".result"; + inline static const std::string COMMENT_PREFIX = "#"; + inline static const std::string END_LINE_SUFFIX = ";"; + inline static const std::string LOAD_PROCEDURE_CMD_PREFIX = "-- loadProcedure"; + inline static const std::string ERROR_CMD_PREFIX = "-- error"; + inline static const std::string LOAD_PROCEDURE_READ_ONLY = "read_only=true"; + std::string db_dir_ = "./testdb"; + std::string graph_name_ = "default"; + GraphFactory::GRAPH_DATASET_TYPE graph_type_ = GraphFactory::GRAPH_DATASET_TYPE::YAGO; + lgraph::ut::QUERY_TYPE query_type_ = lgraph::ut::QUERY_TYPE::GQL; + + protected: + std::string test_suite_dir_ = lgraph::ut::TEST_RESOURCE_DIRECTORY + "/unit_test"; + + void set_graph_type(GraphFactory::GRAPH_DATASET_TYPE graph_type) { graph_type_ = graph_type; } + + void set_query_type(lgraph::ut::QUERY_TYPE query_type) { query_type_ = query_type; } + + bool diff_file(const std::string& lef, const std::string& rig) { + std::string cmd = fma_common::StringFormatter::Format("diff {} {}", lef, rig); + lgraph::SubProcess diff(cmd, false); + diff.Wait(); + if (diff.GetExitCode() != 0) { + UT_LOG() << "-----" << cmd << "-----"; + UT_LOG() << diff.Stdout(); + } + return diff.GetExitCode() == 0; + } + + void init_db() { + ctx_.reset(); + galaxy_.reset(); + GraphFactory::create_graph(graph_type_, db_dir_); + gconf_.dir = db_dir_; + galaxy_ = std::make_shared(gconf_, true, nullptr); + ctx_ = std::make_shared( + nullptr, galaxy_.get(), lgraph::_detail::DEFAULT_ADMIN_NAME, graph_name_); + ctx_->param_tab_ = g_param_tab; + } + + bool test_gql_case(const std::string& gql, std::string& result) { + if (ctx_ == nullptr) { + UT_LOG() << "ctx_ is nullptr"; + return false; + } + geax::frontend::AntlrGqlParser parser(gql); + parser::GqlParser::GqlRequestContext* rule = parser.gqlRequest(); + if (!parser.error().empty()) { + UT_LOG() << "parser.gqlRequest() error: " << parser.error(); + result = parser.error(); + return false; + } + geax::common::ObjectArenaAllocator objAlloc_; + GQLResolveCtx gql_ctx{objAlloc_}; + GQLAstVisitor visitor{gql_ctx}; + rule->accept(&visitor); + auto ret = visitor.error(); + if (ret != GEAXErrorCode::GEAX_SUCCEED) { + UT_LOG() << "rule->accept(&visitor) ret: " << ToString(ret); + result = ToString(ret); + return false; + } + AstNode* node = visitor.result(); + // rewrite ast + cypher::GenAnonymousAliasRewriter gen_anonymous_alias_rewriter; + node->accept(gen_anonymous_alias_rewriter); + // dump + AstDumper dumper; + ret = dumper.handle(node); + if (ret != GEAXErrorCode::GEAX_SUCCEED) { + UT_LOG() << "dumper.handle(node) gql: " << gql; + UT_LOG() << "dumper.handle(node) ret: " << ToString(ret); + UT_LOG() << "dumper.handle(node) error_msg: " << dumper.error_msg(); + result = dumper.error_msg(); + return false; + } else { + UT_DBG() << "--- dumper.handle(node) dump ---"; + UT_DBG() << dumper.dump(); + } + cypher::ExecutionPlanV2 execution_plan_v2; + ret = execution_plan_v2.Build(node); + if (ret != GEAXErrorCode::GEAX_SUCCEED) { + UT_LOG() << "build execution_plan_v2 failed: " << execution_plan_v2.ErrorMsg(); + result = execution_plan_v2.ErrorMsg(); + return false; + } else { + try { + execution_plan_v2.Execute(ctx_.get()); + } catch (std::exception& e) { + UT_LOG() << e.what(); + result = e.what(); + return false; + } + UT_LOG() << "-----result-----"; + result = ctx_->result_->Dump(false); + UT_LOG() << result; + } + return true; + } + + bool test_cypher_case(const std::string& cypher, std::string& result) { + try { + antlr4::ANTLRInputStream input(cypher); + parser::LcypherLexer lexer(&input); + antlr4::CommonTokenStream tokens(&lexer); + parser::LcypherParser parser(&tokens); + parser.addErrorListener(&parser::CypherErrorListener::INSTANCE); + geax::common::ObjectArenaAllocator objAlloc_; + parser::CypherBaseVisitorV2 visitor(objAlloc_, parser.oC_Cypher()); + AstNode* node = visitor.result(); + // rewrite ast + cypher::GenAnonymousAliasRewriter gen_anonymous_alias_rewriter; + node->accept(gen_anonymous_alias_rewriter); + // dump + AstDumper dumper; + auto ret = dumper.handle(node); + if (ret != GEAXErrorCode::GEAX_SUCCEED) { + UT_LOG() << "dumper.handle(node) gql: " << cypher; + UT_LOG() << "dumper.handle(node) ret: " << ToString(ret); + UT_LOG() << "dumper.handle(node) error_msg: " << dumper.error_msg(); + result = dumper.error_msg(); + return false; + } else { + UT_DBG() << "--- dumper.handle(node) dump ---"; + UT_DBG() << dumper.dump(); + } + LOG_INFO() << "------------------------- " << __FILE__ << " " << __LINE__; + cypher::ExecutionPlanV2 execution_plan_v2; + ret = execution_plan_v2.Build(node); + if (ret != GEAXErrorCode::GEAX_SUCCEED) { + UT_LOG() << "build execution_plan_v2 failed: " << execution_plan_v2.ErrorMsg(); + result = execution_plan_v2.ErrorMsg(); + return false; + } else { + try { + execution_plan_v2.Execute(ctx_.get()); + } catch (std::exception& e) { + UT_LOG() << e.what(); + result = e.what(); + return false; + } + UT_LOG() << "-----result-----"; + result = ctx_->result_->Dump(false); + UT_LOG() << result; + } + } catch (std::exception& e) { + UT_LOG() << e.what(); + result = e.what(); + return false; + } + return true; + } + + void test_files(const std::string& dir) { + fma_common::LocalFileSystem fs; + for (auto& file : fs.ListFiles(dir)) { + if (fma_common::EndsWith(file, TEST_SUFFIX)) { + test_file(file.substr(0, file.size() - TEST_SUFFIX.size())); + } + } + } + + void test_file(const std::string& file_prefix, bool check_result = true) { + std::string test_file = file_prefix + TEST_SUFFIX; + std::string result_file = file_prefix + RESULT_SUFFIX; + std::string real_file = file_prefix + REAL_SUFFIX; + std::string line, query, result; + bool is_error = false; + fma_common::LocalFileSystem fs; + if (!fs.FileExists(test_file)) { + UT_ERR() << "test_file not exists: " << test_file; + UT_EXPECT_TRUE(false); + return; + } + std::ifstream test_file_in(test_file); + std::ofstream real_file_out(real_file); + init_db(); + UT_DBG() << "test_file: " << test_file; + auto test_query_handle_result = [&]() { + UT_LOG() << "-----" << lgraph::ut::ToString(query_type_) << "-----"; + UT_LOG() << query; + bool success; + if (query_type_ == lgraph::ut::QUERY_TYPE::NEWCYPHER) { + success = test_cypher_case(query, result); + } else if (query_type_ == lgraph::ut::QUERY_TYPE::GQL) { + success = test_gql_case(query, result); + } else { + LOG_FATAL() << "unhandled query_type_: " << lgraph::ut::ToString(query_type_); + UT_EXPECT_TRUE(false); + return; + } + if (!success && !is_error) { + UT_EXPECT_TRUE(false); + } + real_file_out << query << std::endl; + real_file_out << result << std::endl; + query.clear(); + is_error = false; + }; + while (std::getline(test_file_in, line)) { + std::string line_t = fma_common::Strip(line, ' '); + bool start_with_comment_prefix = fma_common::StartsWith(line_t, COMMENT_PREFIX); + if (start_with_comment_prefix || line_t.empty()) { + real_file_out << line << std::endl; + continue; + } + if (fma_common::StartsWith(line_t, ERROR_CMD_PREFIX)) { + real_file_out << line << std::endl; + is_error = true; + continue; + } else if (fma_common::StartsWith(line_t, LOAD_PROCEDURE_CMD_PREFIX)) { + // Load stored procedure + // Input format: -- loadProcedure name procedure_source_path [read_only=true] + // The default value for read_only is true. + real_file_out << line << std::endl; + auto args = fma_common::Split(line_t, " "); + if (args.size() / 2 == 2 && !args[2].empty() && !args[3].empty()) { + load_procedure(args[2], args[3], + args.size() != 5 || args[4] == LOAD_PROCEDURE_READ_ONLY); + continue; + } + UT_EXPECT_TRUE(false); + } + if (!query.empty()) { + query += "\n"; + } + query += line; + if (fma_common::EndsWith(line_t, END_LINE_SUFFIX)) { + test_query_handle_result(); + } + } + if (!query.empty()) { + test_query_handle_result(); + } + test_file_in.close(); + real_file_out.close(); + if (!check_result) { + return; + } + if (diff_file(real_file, result_file)) { + fma_common::LocalFileSystem fs; + // fs.Remove(real_file); + fs.Remove(db_dir_); + } else { + UT_EXPECT_TRUE(false); + } + } + + void load_procedure(const std::string& name, const std::string& procedure_source_path, + bool read_only = true) { + std::ifstream f; + LOG_INFO() << "open file " << procedure_source_path; + f.open(procedure_source_path, std::ios::in); + std::string buf; + std::string text = ""; + while (getline(f, buf)) { + text += buf; + text += "\n"; + } + f.close(); + LOG_INFO() << "load_procedure text size " << text.size(); + std::string encoded = lgraph_api::encode_base64(text); + std::string result; + std::string procedure_version = "v1"; + UT_EXPECT_TRUE(test_cypher_case( + FMA_FMT("CALL db.plugin.loadPlugin('CPP','{}','{}','CPP','{}', {}, '{}')", name, + encoded, name, read_only ? "true" : "false", procedure_version), + result)); + return; + } +}; + +TEST_F(TestCypherV2, TestFind) { + set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); + set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); + std::string dir = test_suite_dir_ + "/find/cypher"; + test_files(dir); +} + +// TEST_F(TestCypherV2, TestQuery) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/query/cypher"; +// test_files(dir); +// } + +TEST_F(TestCypherV2, TestHint) { + set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); + set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); + std::string dir = test_suite_dir_ + "/hint/cypher"; + test_files(dir); +} + +// TEST_F(TestCypherV2, TestMultiMatch) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/multi_match/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestOptionalMatch) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/optional_match/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestUnion) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/union/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestFunction) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/function/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestParameter) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/parameter/cypher"; +// test_files(dir); +// } + +TEST_F(TestCypherV2, TestVarLenEdge) { + set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); + set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); + std::string dir = test_suite_dir_ + "/var_len_edge/cypher"; + test_files(dir); +} + +TEST_F(TestCypherV2, TestUniqueness) { + set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); + set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); + std::string dir = test_suite_dir_ + "/uniqueness/cypher"; + test_files(dir); +} + +TEST_F(TestCypherV2, TestFuncFilter) { + set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); + set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); + std::string dir = test_suite_dir_ + "/func_filter/cypher"; + test_files(dir); +} + +// TEST_F(TestCypherV2, TestExpression) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/expression/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestWith) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/with/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestListComprehension) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/list_comprehension/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestProfile) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/profile/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestUnwind) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/unwind/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestProcedure) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/procedure/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestAdd) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/add/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestSet) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/set/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestDelete) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/delete/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestRemove) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/remove/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestOrderby) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/orderby/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestMerge) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/merge/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestCreatYago) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/create_yago/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestAggregate) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/aggregate/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestAlgo) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/algo/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestTopn) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/topn/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestLdbcSnb) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/ldbc_snb/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestOpt) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/opt/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestFixCrashIssues) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/fix_crash_issues/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestUndefinedVar) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/undefined_var/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestCreateLabel) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::EMPTY); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/create_label/cypher"; +// test_files(dir); +// } + +// TEST_F(TestCypherV2, TestEdgeIdQuery) { +// set_graph_type(GraphFactory::GRAPH_DATASET_TYPE::YAGO); +// set_query_type(lgraph::ut::QUERY_TYPE::NEWCYPHER); +// std::string dir = test_suite_dir_ + "/edge_id_query/cypher"; +// test_files(dir); +// } diff --git a/test/ut_types.h b/test/ut_types.h index 0991a369cd..2f2727f7d6 100644 --- a/test/ut_types.h +++ b/test/ut_types.h @@ -22,13 +22,15 @@ namespace lgraph::ut { enum class QUERY_TYPE { CYPHER, - GQL + GQL, + NEWCYPHER }; static std::string ToString(const QUERY_TYPE n) { static const std::unordered_map map = { {QUERY_TYPE::CYPHER, "CYPHER"}, {QUERY_TYPE::GQL, "GQL"}, + {QUERY_TYPE::NEWCYPHER, "NEWCYPHER"}, }; auto it = map.find(n); if (it == map.end()) { @@ -42,6 +44,7 @@ static bool ToType(const std::string& str, QUERY_TYPE& n) { static const std::unordered_map map = { {"CYPHER", QUERY_TYPE::CYPHER}, {"GQL", QUERY_TYPE::GQL}, + {"NEWCYPHER", QUERY_TYPE::NEWCYPHER}, }; auto it = map.find(fma_common::ToUpper(str)); if (it == map.end()) {