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.
- package/README.md +154 -1
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/expressions/expression.d.ts +3 -0
- package/dist/parsing/expressions/expression.d.ts.map +1 -1
- package/dist/parsing/expressions/expression.js +8 -0
- package/dist/parsing/expressions/expression.js.map +1 -1
- package/dist/parsing/expressions/subquery_expression.d.ts +18 -0
- package/dist/parsing/expressions/subquery_expression.d.ts.map +1 -0
- package/dist/parsing/expressions/subquery_expression.js +98 -0
- package/dist/parsing/expressions/subquery_expression.js.map +1 -0
- package/dist/parsing/functions/function_factory.d.ts +11 -0
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +13 -0
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/predicate_all.d.ts +7 -0
- package/dist/parsing/functions/predicate_all.d.ts.map +1 -0
- package/dist/parsing/functions/predicate_all.js +58 -0
- package/dist/parsing/functions/predicate_all.js.map +1 -0
- package/dist/parsing/functions/predicate_any.d.ts +7 -0
- package/dist/parsing/functions/predicate_any.d.ts.map +1 -0
- package/dist/parsing/functions/predicate_any.js +58 -0
- package/dist/parsing/functions/predicate_any.js.map +1 -0
- package/dist/parsing/functions/predicate_function.d.ts +4 -1
- package/dist/parsing/functions/predicate_function.d.ts.map +1 -1
- package/dist/parsing/functions/predicate_function.js +18 -2
- package/dist/parsing/functions/predicate_function.js.map +1 -1
- package/dist/parsing/functions/predicate_none.d.ts +7 -0
- package/dist/parsing/functions/predicate_none.d.ts.map +1 -0
- package/dist/parsing/functions/predicate_none.js +58 -0
- package/dist/parsing/functions/predicate_none.js.map +1 -0
- package/dist/parsing/functions/predicate_single.d.ts +7 -0
- package/dist/parsing/functions/predicate_single.d.ts.map +1 -0
- package/dist/parsing/functions/predicate_single.js +61 -0
- package/dist/parsing/functions/predicate_single.js.map +1 -0
- package/dist/parsing/functions/predicate_sum.js.map +1 -1
- package/dist/parsing/operations/load.d.ts +9 -0
- package/dist/parsing/operations/load.d.ts.map +1 -1
- package/dist/parsing/operations/load.js +48 -0
- package/dist/parsing/operations/load.js.map +1 -1
- package/dist/parsing/operations/return.d.ts.map +1 -1
- package/dist/parsing/operations/return.js +3 -0
- package/dist/parsing/operations/return.js.map +1 -1
- package/dist/parsing/operations/where.d.ts.map +1 -1
- package/dist/parsing/operations/where.js +3 -0
- package/dist/parsing/operations/where.js.map +1 -1
- package/dist/parsing/parser.d.ts +2 -0
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +110 -9
- package/dist/parsing/parser.js.map +1 -1
- package/dist/tokenization/keyword.d.ts +2 -1
- package/dist/tokenization/keyword.d.ts.map +1 -1
- package/dist/tokenization/keyword.js +1 -0
- package/dist/tokenization/keyword.js.map +1 -1
- package/dist/tokenization/token.d.ts +2 -0
- package/dist/tokenization/token.d.ts.map +1 -1
- package/dist/tokenization/token.js +7 -0
- package/dist/tokenization/token.js.map +1 -1
- 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
|