flowquery 1.0.52 → 1.0.54

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 (58) hide show
  1. package/README.md +154 -1
  2. package/dist/flowquery.min.js +1 -1
  3. package/dist/parsing/expressions/expression.d.ts +3 -0
  4. package/dist/parsing/expressions/expression.d.ts.map +1 -1
  5. package/dist/parsing/expressions/expression.js +8 -0
  6. package/dist/parsing/expressions/expression.js.map +1 -1
  7. package/dist/parsing/expressions/subquery_expression.d.ts +18 -0
  8. package/dist/parsing/expressions/subquery_expression.d.ts.map +1 -0
  9. package/dist/parsing/expressions/subquery_expression.js +98 -0
  10. package/dist/parsing/expressions/subquery_expression.js.map +1 -0
  11. package/dist/parsing/functions/function_factory.d.ts +11 -0
  12. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  13. package/dist/parsing/functions/function_factory.js +13 -0
  14. package/dist/parsing/functions/function_factory.js.map +1 -1
  15. package/dist/parsing/functions/predicate_all.d.ts +7 -0
  16. package/dist/parsing/functions/predicate_all.d.ts.map +1 -0
  17. package/dist/parsing/functions/predicate_all.js +58 -0
  18. package/dist/parsing/functions/predicate_all.js.map +1 -0
  19. package/dist/parsing/functions/predicate_any.d.ts +7 -0
  20. package/dist/parsing/functions/predicate_any.d.ts.map +1 -0
  21. package/dist/parsing/functions/predicate_any.js +58 -0
  22. package/dist/parsing/functions/predicate_any.js.map +1 -0
  23. package/dist/parsing/functions/predicate_function.d.ts +4 -1
  24. package/dist/parsing/functions/predicate_function.d.ts.map +1 -1
  25. package/dist/parsing/functions/predicate_function.js +18 -2
  26. package/dist/parsing/functions/predicate_function.js.map +1 -1
  27. package/dist/parsing/functions/predicate_none.d.ts +7 -0
  28. package/dist/parsing/functions/predicate_none.d.ts.map +1 -0
  29. package/dist/parsing/functions/predicate_none.js +58 -0
  30. package/dist/parsing/functions/predicate_none.js.map +1 -0
  31. package/dist/parsing/functions/predicate_single.d.ts +7 -0
  32. package/dist/parsing/functions/predicate_single.d.ts.map +1 -0
  33. package/dist/parsing/functions/predicate_single.js +61 -0
  34. package/dist/parsing/functions/predicate_single.js.map +1 -0
  35. package/dist/parsing/functions/predicate_sum.js.map +1 -1
  36. package/dist/parsing/operations/load.d.ts +9 -0
  37. package/dist/parsing/operations/load.d.ts.map +1 -1
  38. package/dist/parsing/operations/load.js +48 -0
  39. package/dist/parsing/operations/load.js.map +1 -1
  40. package/dist/parsing/operations/return.d.ts.map +1 -1
  41. package/dist/parsing/operations/return.js +3 -0
  42. package/dist/parsing/operations/return.js.map +1 -1
  43. package/dist/parsing/operations/where.d.ts.map +1 -1
  44. package/dist/parsing/operations/where.js +3 -0
  45. package/dist/parsing/operations/where.js.map +1 -1
  46. package/dist/parsing/parser.d.ts +2 -0
  47. package/dist/parsing/parser.d.ts.map +1 -1
  48. package/dist/parsing/parser.js +110 -9
  49. package/dist/parsing/parser.js.map +1 -1
  50. package/dist/tokenization/keyword.d.ts +2 -1
  51. package/dist/tokenization/keyword.d.ts.map +1 -1
  52. package/dist/tokenization/keyword.js +1 -0
  53. package/dist/tokenization/keyword.js.map +1 -1
  54. package/dist/tokenization/token.d.ts +2 -0
  55. package/dist/tokenization/token.d.ts.map +1 -1
  56. package/dist/tokenization/token.js +7 -0
  57. package/dist/tokenization/token.js.map +1 -1
  58. package/package.json +8 -5
package/README.md CHANGED
@@ -30,7 +30,7 @@ The combination of graph querying and pipeline processing makes FlowQuery ideal
30
30
  └──────────┘
31
31
  ```
32
32
 
33
- See the [Language Reference](#language-reference) and [Quick Cheat Sheet](#quick-cheat-sheet) for full syntax documentation.
33
+ See the [Language Reference](#language-reference) and [Quick Cheat Sheet](#quick-cheat-sheet) for full syntax documentation. For a complete worked example, see [Virtual Org Chart](#virtual-org-chart).
34
34
 
35
35
  FlowQuery is written in TypeScript and runs both in the browser and in Node.js as a self-contained single-file JavaScript library. A pure Python implementation of FlowQuery with full functional fidelity is also available in the [flowquery-py](./flowquery-py) sub-folder (`pip install flowquery`).
36
36
 
@@ -393,6 +393,29 @@ RETURN sum(n IN [1, 2, 3] | n) AS sum // 6
393
393
  RETURN sum(n IN [1+2+3, 2, 3] | n^2) AS sum // 49
394
394
  ```
395
395
 
396
+ ### Boolean Predicate Functions
397
+
398
+ Test list elements against a condition. Follow standard Cypher syntax.
399
+
400
+ ```cypher
401
+ // any — true if at least one element matches
402
+ RETURN any(n IN [1, 2, 3] WHERE n > 2) // true
403
+
404
+ // all — true if every element matches
405
+ RETURN all(n IN [2, 4, 6] WHERE n > 0) // true
406
+
407
+ // none — true if no element matches
408
+ RETURN none(n IN [1, 2, 3] WHERE n > 5) // true
409
+
410
+ // single — true if exactly one element matches
411
+ RETURN single(n IN [1, 2, 3] WHERE n > 2) // true
412
+
413
+ // In a WHERE clause
414
+ UNWIND [[1,2,3], [4,5,6]] AS nums
415
+ WITH nums WHERE any(n IN nums WHERE n > 4)
416
+ RETURN nums // [4, 5, 6]
417
+ ```
418
+
396
419
  ### Aggregate Functions
397
420
 
398
421
  Used in `RETURN` or `WITH` to group and reduce rows. Non-aggregated expressions define grouping keys. Aggregate functions cannot be nested.
@@ -552,6 +575,44 @@ MATCH (a:Person), (b:Person) WHERE (a)-[:KNOWS]->(b) RETURN a.name, b.name
552
575
  MATCH (a:Person) WHERE NOT (a)-[:KNOWS]->(:Person) RETURN a.name
553
576
  ```
554
577
 
578
+ **Subquery Expressions:** `EXISTS`, `COUNT`, and `COLLECT` evaluate a full subquery as an expression. The subquery can reference outer-scope variables and supports the complete FlowQuery pipeline (MATCH, WITH, WHERE, UNWIND, LOAD, etc.).
579
+
580
+ ```cypher
581
+ // EXISTS — returns true if the subquery produces any rows
582
+ MATCH (p:Person)
583
+ WHERE EXISTS {
584
+ MATCH (p)-[:KNOWS]->(friend:Person)
585
+ WHERE friend.age > 30
586
+ }
587
+ RETURN p.name
588
+
589
+ // NOT EXISTS — negate with NOT
590
+ MATCH (p:Person)
591
+ WHERE NOT EXISTS { MATCH (p)-[:KNOWS]->(:Person) }
592
+ RETURN p.name
593
+
594
+ // COUNT — returns the number of rows the subquery produces
595
+ MATCH (p:Person)
596
+ WHERE COUNT { MATCH (p)-[:KNOWS]->(:Person) } > 2
597
+ RETURN p.name
598
+
599
+ // COUNT in RETURN
600
+ MATCH (p:Person)
601
+ RETURN p.name, COUNT { MATCH (p)-[:KNOWS]->(:Person) } AS friendCount
602
+
603
+ // COLLECT — returns a list of single-column values from the subquery
604
+ MATCH (p:Person)
605
+ RETURN COLLECT {
606
+ MATCH (p)-[:KNOWS]->(friend:Person)
607
+ RETURN friend.name
608
+ } AS friends
609
+
610
+ // COLLECT with IN
611
+ MATCH (p:Person)
612
+ WHERE 'Alice' IN COLLECT { MATCH (p)-[:KNOWS]->(f:Person) RETURN f.name }
613
+ RETURN p.name
614
+ ```
615
+
555
616
  **Node reference reuse across MATCH clauses:**
556
617
 
557
618
  ```cypher
@@ -674,6 +735,8 @@ RETURN f.name, f.description, f.category
674
735
  │ CONTAINS · NOT CONTAINS │
675
736
  │ STARTS WITH · NOT STARTS WITH │
676
737
  │ ENDS WITH · NOT ENDS WITH │
738
+ │ EXISTS { subquery } · NOT EXISTS { subquery } │
739
+ │ COUNT { subquery } · COLLECT { subquery } │
677
740
  ├─────────────────────────────────────────────────────────────┤
678
741
  │ EXPRESSIONS │
679
742
  ├─────────────────────────────────────────────────────────────┤
@@ -698,6 +761,10 @@ RETURN f.name, f.description, f.category
698
761
  │ sum(x) avg(x) count(x) min(x) max(x) collect(x) │
699
762
  │ count(DISTINCT x) · collect(DISTINCT x) │
700
763
  │ sum(v IN list | expr [WHERE cond]) -- inline predicate │
764
+ │ any(v IN list WHERE cond) -- true if any match │
765
+ │ all(v IN list WHERE cond) -- true if all match │
766
+ │ none(v IN list WHERE cond) -- true if none match │
767
+ │ single(v IN list WHERE cond) -- true if one match │
701
768
  ├─────────────────────────────────────────────────────────────┤
702
769
  │ SCALAR FUNCTIONS │
703
770
  ├─────────────────────────────────────────────────────────────┤
@@ -891,6 +958,92 @@ WITH f WHERE f.name = 'double'
891
958
  RETURN f.name AS name, f.description AS description, f.category AS category
892
959
  ```
893
960
 
961
+ ## Examples
962
+
963
+ ### Virtual Org Chart
964
+
965
+ This single multi-statement query creates a virtual graph for a fictitious company — complete with employees, skills, phone numbers, and a management chain — then queries it to produce an org chart. [Try live!](https://microsoft.github.io/FlowQuery/?rZXPbtNAEMbFhUMOReXAeW4OwkH521ZBQgolrVQlSogDQlRVtdjTeKm9a603Bavqw_AAPEVfDO16s_EmEVElfPHuzGf7N9-M7UN4BfX-MM0SXiC-hkEA9zUAgJdwqc_quKdRH1o-MJJiH7yACAKnMTLP1-kf_PucykSlTocTE6weEWZEyBSZ7IM3_IXhUtI71MIs5kxd-KbV6PV6jWar2fR8yG9pkuR9uPQCKYjEReH54I2QRCjymGZqd0YZYSF6Vw--C9q2oGMiwmUOM3qHgnh-FfTLFPgNDNmCMkRB2ULTuKBOchO03Ww5oAMRxlRiKJdCVeadJnwZqcUYmeT6JlukHUs6FbQgMCUSEw2yRToVPFqG0prrkLrJTdLOBumMkyglWVbW5Q0YSQpJw1xtPn_dpuxayguSYg4fBOe3Sl2lDJBRLqyhBuVJfrYdynmRYRAKmqmyvGkhY67mzTsXJIs_jbYxexZzRBl8i4np6f_G7LhmLnMNGBS5xFR7-BHvJlm-DXhkAQepeoMueMxyXVQF0LQSxoSRxW7Afd12fQxCsUw1FpEEdLNzqjkDSW4x5kmEAsaLVG4TH1viOU8ff-dwTkT4-Ids9p7fyJ9EoGvrk0ztuqYi0fVtDMEcc7nzPTqxnGdE0pTAIGkEpMDI9XYX55Moew7leibHI2vwlGaYUIaq_xrySn1SBYZcRHp_YDZvaaQyNPJXAVWCCqmzDa7wVWK1XlcPsNKt61DK9c7eSFejcnphw2U5Kl6uag_vaofuP6Fx2Z8Np5PZPLieT64a-_8WCd7Ia_MlFnQRl5tWtWtW0tkv6VYl7Z2S3n7JUVXS2Sk5rkq6OyUnruTfHTZXqbRZWttXN9GXmrWy_gXUce1v7RnUt_x_X08XoqI50A_FcnzWxyAANBrfKOwsWYVcjxNWR8ikK2NkNOUUVR9SjpNJm2mqpMtImU8XwqXUvmVcyHzOa88dBN9U9Bc)
966
+
967
+ ```cypher
968
+ CREATE VIRTUAL (:Employee) AS {
969
+ UNWIND [
970
+ {id: 1, name: 'Sara Chen', jobTitle: 'CEO', department: 'Executive', phone: '+1-555-0100', skills: ['Strategy', 'Leadership', 'Finance']},
971
+ {id: 2, name: 'Marcus Rivera', jobTitle: 'VP of Engineering', department: 'Engineering', phone: '+1-555-0201', skills: ['Architecture', 'Cloud', 'Mentoring']},
972
+ {id: 3, name: 'Priya Patel', jobTitle: 'VP of Product', department: 'Product', phone: '+1-555-0301', skills: ['Roadmapping', 'Analytics', 'UX']},
973
+ {id: 4, name: 'James Brooks', jobTitle: 'Senior Engineer', department: 'Engineering', phone: '+1-555-0202', skills: ['TypeScript', 'Python', 'GraphQL']},
974
+ {id: 5, name: 'Lin Zhang', jobTitle: 'Senior Engineer', department: 'Engineering', phone: '+1-555-0203', skills: ['Rust', 'Systems', 'DevOps']},
975
+ {id: 6, name: 'Amara Johnson', jobTitle: 'Product Manager', department: 'Product', phone: '+1-555-0302', skills: ['Scrum', 'Data Analysis', 'Stakeholder Mgmt']},
976
+ {id: 7, name: 'Tomás García', jobTitle: 'Software Engineer', department: 'Engineering', phone: '+1-555-0204', skills: ['React', 'TypeScript', 'Testing']},
977
+ {id: 8, name: 'Fatima Al-Sayed', jobTitle: 'Software Engineer', department: 'Engineering', phone: '+1-555-0205', skills: ['Python', 'ML', 'Data Pipelines']}
978
+ ] AS record
979
+ RETURN record.id AS id, record.name AS name, record.jobTitle AS jobTitle,
980
+ record.department AS department, record.phone AS phone, record.skills AS skills
981
+ };
982
+ CREATE VIRTUAL (:Employee)-[:REPORTS_TO]-(:Employee) AS {
983
+ UNWIND [
984
+ {left_id: 2, right_id: 1},
985
+ {left_id: 3, right_id: 1},
986
+ {left_id: 4, right_id: 2},
987
+ {left_id: 5, right_id: 2},
988
+ {left_id: 6, right_id: 3},
989
+ {left_id: 7, right_id: 4},
990
+ {left_id: 8, right_id: 4}
991
+ ] AS record
992
+ RETURN record.left_id AS left_id, record.right_id AS right_id
993
+ };
994
+ MATCH (e:Employee)
995
+ OPTIONAL MATCH (e)-[:REPORTS_TO]->(mgr:Employee)
996
+ RETURN
997
+ e.name AS employee,
998
+ e.jobTitle AS title,
999
+ e.department AS department,
1000
+ e.phone AS phone,
1001
+ e.skills AS skills,
1002
+ mgr.name AS reportsTo
1003
+ ORDER BY e.department, e.name
1004
+ ```
1005
+
1006
+ Output:
1007
+
1008
+ | employee | title | department | phone | skills | reportsTo |
1009
+ | --------------- | ----------------- | ----------- | ----------- | ---------------------------------------- | ------------- |
1010
+ | Fatima Al-Sayed | Software Engineer | Engineering | +1-555-0205 | [Python, ML, Data Pipelines] | James Brooks |
1011
+ | James Brooks | Senior Engineer | Engineering | +1-555-0202 | [TypeScript, Python, GraphQL] | Marcus Rivera |
1012
+ | Lin Zhang | Senior Engineer | Engineering | +1-555-0203 | [Rust, Systems, DevOps] | Marcus Rivera |
1013
+ | Marcus Rivera | VP of Engineering | Engineering | +1-555-0201 | [Architecture, Cloud, Mentoring] | Sara Chen |
1014
+ | Tomás García | Software Engineer | Engineering | +1-555-0204 | [React, TypeScript, Testing] | James Brooks |
1015
+ | Sara Chen | CEO | Executive | +1-555-0100 | [Strategy, Leadership, Finance] | null |
1016
+ | Amara Johnson | Product Manager | Product | +1-555-0302 | [Scrum, Data Analysis, Stakeholder Mgmt] | Priya Patel |
1017
+ | Priya Patel | VP of Product | Product | +1-555-0301 | [Roadmapping, Analytics, UX] | Sara Chen |
1018
+
1019
+ You can further explore the graph — for example, find the full management chain from any employee up to the CEO:
1020
+
1021
+ ```cypher
1022
+ MATCH (e:Employee)-[:REPORTS_TO*1..]->(mgr:Employee)
1023
+ WHERE e.name = 'Tomás García'
1024
+ RETURN e.name AS employee, collect(mgr.name) AS managementChain
1025
+ // [{ employee: "Tomás García", managementChain: ["James Brooks", "Marcus Rivera", "Sara Chen"] }]
1026
+ ```
1027
+
1028
+ Or find each manager's direct reports:
1029
+
1030
+ ```cypher
1031
+ MATCH (dr:Employee)-[:REPORTS_TO]->(mgr:Employee)
1032
+ RETURN mgr.name AS manager, collect(dr.name) AS directReports
1033
+ ORDER BY manager
1034
+ ```
1035
+
1036
+ Or find all employees who share a skill:
1037
+
1038
+ ```cypher
1039
+ MATCH (a:Employee), (b:Employee)
1040
+ WHERE a.id < b.id
1041
+ WITH a, b, [s IN a.skills WHERE s IN b.skills] AS shared
1042
+ WHERE size(shared) > 0
1043
+ RETURN a.name AS employee1, b.name AS employee2, shared AS sharedSkills
1044
+ ORDER BY size(shared) DESC
1045
+ ```
1046
+
894
1047
  ## Contributing
895
1048
 
896
1049
  This project welcomes contributions and suggestions. Most contributions require you to agree to a