flowquery 1.0.26 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/flowquery.min.js +1 -1
  2. package/dist/graph/relationship.d.ts.map +1 -1
  3. package/dist/graph/relationship.js +5 -1
  4. package/dist/graph/relationship.js.map +1 -1
  5. package/dist/parsing/base_parser.d.ts +1 -1
  6. package/dist/parsing/base_parser.d.ts.map +1 -1
  7. package/dist/parsing/base_parser.js.map +1 -1
  8. package/dist/parsing/expressions/operator.d.ts +37 -1
  9. package/dist/parsing/expressions/operator.d.ts.map +1 -1
  10. package/dist/parsing/expressions/operator.js +121 -2
  11. package/dist/parsing/expressions/operator.js.map +1 -1
  12. package/dist/parsing/expressions/reference.d.ts +1 -0
  13. package/dist/parsing/expressions/reference.d.ts.map +1 -1
  14. package/dist/parsing/expressions/reference.js +3 -0
  15. package/dist/parsing/expressions/reference.js.map +1 -1
  16. package/dist/parsing/functions/function_factory.d.ts +1 -0
  17. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  18. package/dist/parsing/functions/function_factory.js +1 -0
  19. package/dist/parsing/functions/function_factory.js.map +1 -1
  20. package/dist/parsing/functions/string_distance.d.ts +7 -0
  21. package/dist/parsing/functions/string_distance.d.ts.map +1 -0
  22. package/dist/parsing/functions/string_distance.js +84 -0
  23. package/dist/parsing/functions/string_distance.js.map +1 -0
  24. package/dist/parsing/parser.d.ts +6 -0
  25. package/dist/parsing/parser.d.ts.map +1 -1
  26. package/dist/parsing/parser.js +127 -15
  27. package/dist/parsing/parser.js.map +1 -1
  28. package/dist/tokenization/keyword.d.ts +4 -1
  29. package/dist/tokenization/keyword.d.ts.map +1 -1
  30. package/dist/tokenization/keyword.js +3 -0
  31. package/dist/tokenization/keyword.js.map +1 -1
  32. package/dist/tokenization/token.d.ts +6 -0
  33. package/dist/tokenization/token.d.ts.map +1 -1
  34. package/dist/tokenization/token.js +18 -0
  35. package/dist/tokenization/token.js.map +1 -1
  36. package/docs/flowquery.min.js +1 -1
  37. package/flowquery-py/pyproject.toml +1 -1
  38. package/flowquery-py/src/graph/relationship.py +5 -1
  39. package/flowquery-py/src/parsing/expressions/__init__.py +4 -0
  40. package/flowquery-py/src/parsing/expressions/operator.py +102 -0
  41. package/flowquery-py/src/parsing/functions/__init__.py +2 -0
  42. package/flowquery-py/src/parsing/functions/string_distance.py +88 -0
  43. package/flowquery-py/src/parsing/parser.py +120 -10
  44. package/flowquery-py/src/tokenization/keyword.py +3 -0
  45. package/flowquery-py/src/tokenization/token.py +21 -0
  46. package/flowquery-py/tests/compute/test_runner.py +406 -1
  47. package/flowquery-py/tests/parsing/test_expression.py +121 -1
  48. package/flowquery-py/tests/parsing/test_parser.py +203 -0
  49. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  50. package/package.json +1 -1
  51. package/src/graph/relationship.ts +4 -1
  52. package/src/parsing/base_parser.ts +1 -1
  53. package/src/parsing/expressions/operator.ts +129 -1
  54. package/src/parsing/expressions/reference.ts +8 -5
  55. package/src/parsing/functions/function_factory.ts +1 -0
  56. package/src/parsing/functions/string_distance.ts +80 -0
  57. package/src/parsing/parser.ts +138 -14
  58. package/src/tokenization/keyword.ts +3 -0
  59. package/src/tokenization/token.ts +24 -0
  60. package/tests/compute/runner.test.ts +379 -0
  61. package/tests/parsing/expression.test.ts +150 -16
  62. package/tests/parsing/parser.test.ts +200 -0
@@ -8,7 +8,9 @@ from flowquery.parsing.functions.function_metadata import FunctionDef
8
8
  from flowquery.parsing.operations.match import Match
9
9
  from flowquery.parsing.operations.create_relationship import CreateRelationship
10
10
  from flowquery.graph.node import Node
11
+ from flowquery.graph.node_reference import NodeReference
11
12
  from flowquery.graph.relationship import Relationship
13
+ from flowquery.graph.relationship_reference import RelationshipReference
12
14
 
13
15
 
14
16
  # Test async function for CALL operation parsing test
@@ -821,6 +823,35 @@ class TestParser:
821
823
  assert relationship.properties.get("since") is not None
822
824
  assert relationship.properties["since"].value() == 2022
823
825
 
826
+ def test_node_reference_with_label_creates_node_reference(self):
827
+ """Test that reusing a variable with a label creates a NodeReference instead of a new node."""
828
+ parser = Parser()
829
+ ast = parser.parse("MATCH (n:Person)-[:KNOWS]->(n:Person) RETURN n")
830
+ match_op = ast.first_child()
831
+ assert isinstance(match_op, Match)
832
+ first_node = match_op.patterns[0].chain[0]
833
+ second_node = match_op.patterns[0].chain[2]
834
+ assert isinstance(first_node, Node)
835
+ assert first_node.identifier == "n"
836
+ assert first_node.label == "Person"
837
+ assert isinstance(second_node, NodeReference)
838
+ assert second_node.reference.identifier == "n"
839
+ assert second_node.label == "Person"
840
+
841
+ def test_relationship_reference_with_type_creates_relationship_reference(self):
842
+ """Test that reusing a relationship variable with a type creates a RelationshipReference."""
843
+ parser = Parser()
844
+ ast = parser.parse("MATCH (a:Person)-[r:KNOWS]->(b:Person)-[r:KNOWS]->(c:Person) RETURN a, b, c")
845
+ match_op = ast.first_child()
846
+ assert isinstance(match_op, Match)
847
+ first_rel = match_op.patterns[0].chain[1]
848
+ second_rel = match_op.patterns[0].chain[3]
849
+ assert isinstance(first_rel, Relationship)
850
+ assert first_rel.identifier == "r"
851
+ assert first_rel.type == "KNOWS"
852
+ assert isinstance(second_rel, RelationshipReference)
853
+ assert second_rel.type == "KNOWS"
854
+
824
855
  def test_case_statement_with_keywords_as_identifiers(self):
825
856
  """Test that CASE/WHEN/THEN/ELSE/END are not treated as identifiers."""
826
857
  parser = Parser()
@@ -829,3 +860,175 @@ class TestParser:
829
860
  assert "When" in ast.print()
830
861
  assert "Then" in ast.print()
831
862
  assert "Else" in ast.print()
863
+
864
+ def test_where_with_in_list_check(self):
865
+ """Test WHERE with IN list check."""
866
+ parser = Parser()
867
+ ast = parser.parse("with 1 as n where n IN [1, 2, 3] return n")
868
+ expected = (
869
+ "ASTNode\n"
870
+ "- With\n"
871
+ "-- Expression (n)\n"
872
+ "--- Number (1)\n"
873
+ "- Where\n"
874
+ "-- Expression\n"
875
+ "--- In\n"
876
+ "---- Reference (n)\n"
877
+ "---- JSONArray\n"
878
+ "----- Expression\n"
879
+ "------ Number (1)\n"
880
+ "----- Expression\n"
881
+ "------ Number (2)\n"
882
+ "----- Expression\n"
883
+ "------ Number (3)\n"
884
+ "- Return\n"
885
+ "-- Expression (n)\n"
886
+ "--- Reference (n)"
887
+ )
888
+ assert ast.print() == expected
889
+
890
+ def test_where_with_not_in_list_check(self):
891
+ """Test WHERE with NOT IN list check."""
892
+ parser = Parser()
893
+ ast = parser.parse("with 4 as n where n NOT IN [1, 2, 3] return n")
894
+ expected = (
895
+ "ASTNode\n"
896
+ "- With\n"
897
+ "-- Expression (n)\n"
898
+ "--- Number (4)\n"
899
+ "- Where\n"
900
+ "-- Expression\n"
901
+ "--- NotIn\n"
902
+ "---- Reference (n)\n"
903
+ "---- JSONArray\n"
904
+ "----- Expression\n"
905
+ "------ Number (1)\n"
906
+ "----- Expression\n"
907
+ "------ Number (2)\n"
908
+ "----- Expression\n"
909
+ "------ Number (3)\n"
910
+ "- Return\n"
911
+ "-- Expression (n)\n"
912
+ "--- Reference (n)"
913
+ )
914
+ assert ast.print() == expected
915
+
916
+ def test_where_with_contains(self):
917
+ """Test WHERE with CONTAINS."""
918
+ parser = Parser()
919
+ ast = parser.parse("with 'hello' as s where s CONTAINS 'ell' return s")
920
+ expected = (
921
+ "ASTNode\n"
922
+ "- With\n"
923
+ "-- Expression (s)\n"
924
+ "--- String (hello)\n"
925
+ "- Where\n"
926
+ "-- Expression\n"
927
+ "--- Contains\n"
928
+ "---- Reference (s)\n"
929
+ "---- String (ell)\n"
930
+ "- Return\n"
931
+ "-- Expression (s)\n"
932
+ "--- Reference (s)"
933
+ )
934
+ assert ast.print() == expected
935
+
936
+ def test_where_with_not_contains(self):
937
+ """Test WHERE with NOT CONTAINS."""
938
+ parser = Parser()
939
+ ast = parser.parse("with 'hello' as s where s NOT CONTAINS 'xyz' return s")
940
+ expected = (
941
+ "ASTNode\n"
942
+ "- With\n"
943
+ "-- Expression (s)\n"
944
+ "--- String (hello)\n"
945
+ "- Where\n"
946
+ "-- Expression\n"
947
+ "--- NotContains\n"
948
+ "---- Reference (s)\n"
949
+ "---- String (xyz)\n"
950
+ "- Return\n"
951
+ "-- Expression (s)\n"
952
+ "--- Reference (s)"
953
+ )
954
+ assert ast.print() == expected
955
+
956
+ def test_where_with_starts_with(self):
957
+ """Test WHERE with STARTS WITH."""
958
+ parser = Parser()
959
+ ast = parser.parse("with 'hello' as s where s STARTS WITH 'hel' return s")
960
+ expected = (
961
+ "ASTNode\n"
962
+ "- With\n"
963
+ "-- Expression (s)\n"
964
+ "--- String (hello)\n"
965
+ "- Where\n"
966
+ "-- Expression\n"
967
+ "--- StartsWith\n"
968
+ "---- Reference (s)\n"
969
+ "---- String (hel)\n"
970
+ "- Return\n"
971
+ "-- Expression (s)\n"
972
+ "--- Reference (s)"
973
+ )
974
+ assert ast.print() == expected
975
+
976
+ def test_where_with_not_starts_with(self):
977
+ """Test WHERE with NOT STARTS WITH."""
978
+ parser = Parser()
979
+ ast = parser.parse("with 'hello' as s where s NOT STARTS WITH 'xyz' return s")
980
+ expected = (
981
+ "ASTNode\n"
982
+ "- With\n"
983
+ "-- Expression (s)\n"
984
+ "--- String (hello)\n"
985
+ "- Where\n"
986
+ "-- Expression\n"
987
+ "--- NotStartsWith\n"
988
+ "---- Reference (s)\n"
989
+ "---- String (xyz)\n"
990
+ "- Return\n"
991
+ "-- Expression (s)\n"
992
+ "--- Reference (s)"
993
+ )
994
+ assert ast.print() == expected
995
+
996
+ def test_where_with_ends_with(self):
997
+ """Test WHERE with ENDS WITH."""
998
+ parser = Parser()
999
+ ast = parser.parse("with 'hello' as s where s ENDS WITH 'llo' return s")
1000
+ expected = (
1001
+ "ASTNode\n"
1002
+ "- With\n"
1003
+ "-- Expression (s)\n"
1004
+ "--- String (hello)\n"
1005
+ "- Where\n"
1006
+ "-- Expression\n"
1007
+ "--- EndsWith\n"
1008
+ "---- Reference (s)\n"
1009
+ "---- String (llo)\n"
1010
+ "- Return\n"
1011
+ "-- Expression (s)\n"
1012
+ "--- Reference (s)"
1013
+ )
1014
+ assert ast.print() == expected
1015
+
1016
+ def test_where_with_not_ends_with(self):
1017
+ """Test WHERE with NOT ENDS WITH."""
1018
+ parser = Parser()
1019
+ ast = parser.parse("with 'hello' as s where s NOT ENDS WITH 'xyz' return s")
1020
+ expected = (
1021
+ "ASTNode\n"
1022
+ "- With\n"
1023
+ "-- Expression (s)\n"
1024
+ "--- String (hello)\n"
1025
+ "- Where\n"
1026
+ "-- Expression\n"
1027
+ "--- NotEndsWith\n"
1028
+ "---- Reference (s)\n"
1029
+ "---- String (xyz)\n"
1030
+ "- Return\n"
1031
+ "-- Expression (s)\n"
1032
+ "--- Reference (s)"
1033
+ )
1034
+ assert ast.print() == expected