diff --git a/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.multiStats.adoc b/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.multiStats.adoc index 929484fd20..f87f218d49 100644 --- a/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.multiStats.adoc +++ b/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.multiStats.adoc @@ -22,7 +22,7 @@ apoc.agg.multiStats(value :: NODE | RELATIONSHIP, keys :: LIST OF STRING) :: (MA |=== -[[usage-apoc.data.email]] +[[usage-apoc.agg.multiStats]] == Usage Examples Given this dataset: diff --git a/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.rollup.adoc b/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.rollup.adoc new file mode 100644 index 0000000000..3d060fda96 --- /dev/null +++ b/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/apoc.agg.rollup.adoc @@ -0,0 +1,259 @@ + += apoc.agg.rollup +:description: This section contains reference documentation for the apoc.agg.rollup function. + +label:function[] label:apoc-extended[] + +[.emphasis] +apoc.agg.rollup(, [groupKeys], [aggKeys]) + +Emulate an Oracle/Mysql ROLLUP command: +`ROLLUP groupKeys, SUM(aggKey1), AVG(aggKey1), COUNT(aggKey1), SUM(aggKey2), AVG(aggKey2), ...`. + +Note that the `[NULL]` values (see the `Interpreting "[NULL]" Values in Results` section https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32084[here]) +are returned by the procedure as `[NULL]`. + + + +== Signature + +[source] +---- +apoc.agg.rollup(value :: ANY | RELATIONSHIP, groupKeys :: LIST OF STRING, aggKeys :: LIST OF STRING) :: (MAP?) +---- + +== Config parameters +include::partial$usage/config/apoc.agg.rollup.adoc[] + +[[usage-apoc.agg.rollup]] +== Usage Examples + +Given this dataset: + +[source, cypher] +---- +CREATE (:Product {SupplierID: 1, CategoryID: 1, anotherID: 1, Price: 18, otherNum: 0.3}), + (:Product {SupplierID: 11, CategoryID: 3, anotherID: 1, Price: 14.0, otherNum: 0.1}), + (:Product {SupplierID: 11, CategoryID: 3, anotherID: 0, Price: 31.0, otherNum: 2}), + (:Product {SupplierID: 11, CategoryID: 4, anotherID: 0, Price: 44, otherNum: 0.7}), + (:Product {SupplierID: 1, CategoryID: null, anotherID: 1, Price: 18, otherNum: 0.7}), + (:Product {SupplierID: null, CategoryID: null, anotherID: 0, Price: 18, otherNum: 0.6}), + (:Product {SupplierID: null, CategoryID: 2, anotherID: 0, Price: 199, otherNum: 0.8}); +---- + +We can emulate a https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32084[ROLLUP] clause +like this: +``` +SELECT SupplierID, CategoryID, anotherID, + SUM(Price), AVG(Price), COUNT(Price), SUM(otherNum), AVG(otherNum), COUNT(otherNum) + GROUP BY ROLLUP(SupplierID, CategoryID, anotherID) +``` + +by executing: + +[source, cypher] +---- +MATCH (p:Product) +RETURN apoc.agg.rollup(p, + ["SupplierID", "CategoryID", "anotherID"], + ["Price", "otherNum"] +) as data +---- + + +.Results +[opts="header"] +|=== +| data +a| +[source,json] +---- +[ + {"AVG(otherNum)":0.3,"CategoryID":1,"anotherID":1,"SUM(Price)":18,"COUNT(Price)":1,"AVG(Price)":18,"SUM(otherNum)":0.3,"SupplierID":1,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.3,"CategoryID":1,"anotherID":"[NULL]","SUM(Price)":18,"COUNT(Price)":1,"AVG(Price)":18,"SUM(otherNum)":0.3,"SupplierID":1,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.5,"CategoryID":"[NULL]","anotherID":"[NULL]","SUM(Price)":36,"COUNT(Price)":2,"AVG(Price)":18,"SUM(otherNum)":1,"SupplierID":1,"COUNT(otherNum)":2}, + {"AVG(otherNum)":0.7,"CategoryID":null,"anotherID":1,"SUM(Price)":18,"COUNT(Price)":1,"AVG(Price)":18,"SUM(otherNum)":0.7,"SupplierID":1,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.7,"CategoryID":null,"anotherID":"[NULL]","SUM(Price)":18,"COUNT(Price)":1,"AVG(Price)":18,"SUM(otherNum)":0.7,"SupplierID":1,"COUNT(otherNum)":1}, + {"AVG(otherNum)":2,"CategoryID":3,"anotherID":0,"SUM(Price)":31,"COUNT(Price)":1,"AVG(Price)":31,"SUM(otherNum)":2,"SupplierID":11,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.1,"CategoryID":3,"anotherID":1,"SUM(Price)":14,"COUNT(Price)":1,"AVG(Price)":14,"SUM(otherNum)":0.1,"SupplierID":11,"COUNT(otherNum)":1}, + {"AVG(otherNum)":1.05,"CategoryID":3,"anotherID":"[NULL]","SUM(Price)":45,"COUNT(Price)":2,"AVG(Price)":22.5,"SUM(otherNum)":2.1,"SupplierID":11,"COUNT(otherNum)":2}, + {"AVG(otherNum)":0.7,"CategoryID":4,"anotherID":0,"SUM(Price)":44,"COUNT(Price)":1,"AVG(Price)":44,"SUM(otherNum)":0.7,"SupplierID":11,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.7,"CategoryID":4,"anotherID":"[NULL]","SUM(Price)":44,"COUNT(Price)":1,"AVG(Price)":44,"SUM(otherNum)":0.7,"SupplierID":11,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.9333333333333332,"CategoryID":"[NULL]","anotherID":"[NULL]","SUM(Price)":89,"COUNT(Price)":3,"AVG(Price)":29.666666666666668,"SUM(otherNum)":2.8,"SupplierID":11,"COUNT(otherNum)":3}, + {"AVG(otherNum)":0.7428571428571428,"CategoryID":"[NULL]","anotherID":"[NULL]","SUM(Price)":342,"COUNT(Price)":7,"AVG(Price)":48.857142857142854,"SUM(otherNum)":5.199999999999999,"SupplierID":"[NULL]","COUNT(otherNum)":7}, + {"AVG(otherNum)":0.8,"CategoryID":2,"anotherID":0,"SUM(Price)":199,"COUNT(Price)":1,"AVG(Price)":199,"SUM(otherNum)":0.8,"SupplierID":null,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.8,"CategoryID":2,"anotherID":"[NULL]","SUM(Price)":199,"COUNT(Price)":1,"AVG(Price)":199,"SUM(otherNum)":0.8,"SupplierID":null,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.7,"CategoryID":"[NULL]","anotherID":"[NULL]","SUM(Price)":217,"COUNT(Price)":2,"AVG(Price)":108.5,"SUM(otherNum)":1.4,"SupplierID":null,"COUNT(otherNum)":2}, + {"AVG(otherNum)":0.6,"CategoryID":null,"anotherID":0,"SUM(Price)":18,"COUNT(Price)":1,"AVG(Price)":18,"SUM(otherNum)":0.6,"SupplierID":null,"COUNT(otherNum)":1}, + {"AVG(otherNum)":0.6,"CategoryID":null,"anotherID":"[NULL]","SUM(Price)":18,"COUNT(Price)":1,"AVG(Price)":18,"SUM(otherNum)":0.6,"SupplierID":null,"COUNT(otherNum)":1} +] +---- +|=== + +Note that the `[NULL]` values (see the `Interpreting "[NULL]" Values in Results` section https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32084[here]) +are returned by the procedure as `[NULL]`. + + +or a ROLLUP clause like: +``` +SELECT CategoryID, SupplierID, anotherID, + SUM(Price), AVG(Price), COUNT(Price), SUM(otherNum), AVG(otherNum), COUNT(otherNum) + GROUP BY ROLLUP(CategoryID, SupplierID, anotherID) +``` + + +with this query: + +[source, cypher] +---- +MATCH (p:Product) +RETURN apoc.agg.rollup(p, + ["CategoryID", "SupplierID", "anotherID"], + ["Price", "otherNum"] +) as data +---- + + +.Results +[opts="header"] +|=== +| data +a| +[source,json] +---- +[ + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": 1, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": "[NULL]", "SUM(Price)": 199, "COUNT(Price)": 1, "AVG(Price)": 199.0, "SUM(otherNum)": 0.8, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": 0, "SUM(Price)": 199, "COUNT(Price)": 1, "AVG(Price)": 199.0, "SUM(otherNum)": 0.8, "SupplierID": null, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": "[NULL]", "SUM(Price)": 199, "COUNT(Price)": 1, "AVG(Price)": 199.0, "SUM(otherNum)": 0.8, "SupplierID": null, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 2.0, "CategoryID": 3, "anotherID": 0, "SUM(Price)": 31.0, "COUNT(Price)": 1, "AVG(Price)": 31.0, "SUM(otherNum)": 2, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.1, "CategoryID": 3, "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 1.05, "CategoryID": 3, "anotherID": "[NULL]", "SUM(Price)": 45.0, "COUNT(Price)": 2, "AVG(Price)": 22.5, "SUM(otherNum)": 2.1, "SupplierID": 11, "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 1.05, "CategoryID": 3, "anotherID": "[NULL]", "SUM(Price)": 45.0, "COUNT(Price)": 2, "AVG(Price)": 22.5, "SUM(otherNum)": 2.1, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": 0, "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": "[NULL]", "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": "[NULL]", "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7428571428571428, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 342.0, "COUNT(Price)": 7, "AVG(Price)": 48.857142857142854, "SUM(otherNum)": 5.199999999999999, "SupplierID": "[NULL]", "COUNT(otherNum)": 7}, + { "AVG(otherNum)": 0.7, "CategoryID": null, "anotherID": 1, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.7, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": null, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.7, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.6499999999999999, "CategoryID": null, "anotherID": "[NULL]", "SUM(Price)": 36, "COUNT(Price)": 2, "AVG(Price)": 18.0, "SUM(otherNum)": 1.2999999999999998, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.6, "CategoryID": null, "anotherID": 0, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.6, "SupplierID": null, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.6, "CategoryID": null, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.6, "SupplierID": null, "COUNT(otherNum)": 1} +] +---- +|=== + + +We can also emulate a https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32311[CUBE] clause +like this: +``` +SELECT SupplierID, CategoryID, anotherID, + SUM(Price), AVG(Price), COUNT(Price), SUM(otherNum), AVG(otherNum), COUNT(otherNum) + GROUP BY CUBE(SupplierID, CategoryID, anotherID) +``` + + +executing: + +[source, cypher] +---- +MATCH (p:Product) +RETURN apoc.agg.rollup(p, + ["SupplierID", "CategoryID", "anotherID"], + ["Price", "otherNum"], + {cube: true} +) as data +---- + +.Results +[opts="header"] +|=== +| data +a| +[source,json] +---- +[ + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": 1, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.5666666666666667, "CategoryID": "[NULL]", "anotherID": 1, "SUM(Price)": 54, "COUNT(Price)": 3, "AVG(Price)": 18.0, "SUM(otherNum)": 1.7, "SupplierID": 1, "COUNT(otherNum)": 3}, + { "AVG(otherNum)": 0.5666666666666667, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 54, "COUNT(Price)": 3, "AVG(Price)": 18.0, "SUM(otherNum)": 1.7, "SupplierID": 1, "COUNT(otherNum)": 3}, + { "AVG(otherNum)": 2.0, "CategoryID": 3, "anotherID": 0, "SUM(Price)": 31.0, "COUNT(Price)": 1, "AVG(Price)": 31.0, "SUM(otherNum)": 2, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.1, "CategoryID": 3, "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 1.05, "CategoryID": 3, "anotherID": "[NULL]", "SUM(Price)": 45.0, "COUNT(Price)": 2, "AVG(Price)": 22.5, "SUM(otherNum)": 2.1, "SupplierID": 11, "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": 0, "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": "[NULL]", "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 1.35, "CategoryID": "[NULL]", "anotherID": 0, "SUM(Price)": 75.0, "COUNT(Price)": 2, "AVG(Price)": 37.5, "SUM(otherNum)": 2.7, "SupplierID": 11, "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.1, "CategoryID": "[NULL]", "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.9333333333333332, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 89.0, "COUNT(Price)": 3, "AVG(Price)": 29.666666666666668, "SUM(otherNum)": 2.8, "SupplierID": 11, "COUNT(otherNum)": 3}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": 1, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": 0, "SUM(Price)": 398, "COUNT(Price)": 2, "AVG(Price)": 199.0, "SUM(otherNum)": 1.6, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": "[NULL]", "SUM(Price)": 398, "COUNT(Price)": 2, "AVG(Price)": 199.0, "SUM(otherNum)": 1.6, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 2.0, "CategoryID": 3, "anotherID": 0, "SUM(Price)": 31.0, "COUNT(Price)": 1, "AVG(Price)": 31.0, "SUM(otherNum)": 2, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.1, "CategoryID": 3, "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 1.05, "CategoryID": 3, "anotherID": "[NULL]", "SUM(Price)": 45.0, "COUNT(Price)": 2, "AVG(Price)": 22.5, "SUM(otherNum)": 2.1, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": 0, "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": "[NULL]", "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.8374999999999999, "CategoryID": "[NULL]", "anotherID": 0, "SUM(Price)": 545.0, "COUNT(Price)": 8, "AVG(Price)": 68.125, "SUM(otherNum)": 6.699999999999999, "SupplierID": "[NULL]", "COUNT(otherNum)": 8}, + { "AVG(otherNum)": 0.45, "CategoryID": "[NULL]", "anotherID": 1, "SUM(Price)": 68.0, "COUNT(Price)": 4, "AVG(Price)": 17.0, "SUM(otherNum)": 1.8, "SupplierID": "[NULL]", "COUNT(otherNum)": 4}, + { "AVG(otherNum)": 0.7083333333333331, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 613.0, "COUNT(Price)": 12, "AVG(Price)": 51.083333333333336, "SUM(otherNum)": 8.499999999999998, "SupplierID": "[NULL]", "COUNT(otherNum)": 12} +] +---- +|=== + +or a CUBE clause like: +``` +SELECT CategoryID, SupplierID, anotherID, + SUM(Price), AVG(Price), COUNT(Price), SUM(otherNum), AVG(otherNum), COUNT(otherNum) + GROUP BY CUBE(CategoryID, SupplierID, anotherID) +``` + + +with this query: +[source, cypher] +---- +MATCH (p:Product) +RETURN apoc.agg.rollup(p, + ["CategoryID", "SupplierID", "anotherID"], + ["Price", "otherNum"], + {cube: true} +) as data +---- + +.Results +[opts="header"] +|=== +| data +a| +[source,json] +---- +[ + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": 1, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": 1, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": 1, "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.3, "CategoryID": 1, "anotherID": "[NULL]", "SUM(Price)": 18, "COUNT(Price)": 1, "AVG(Price)": 18.0, "SUM(otherNum)": 0.3, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": 0, "SUM(Price)": 398, "COUNT(Price)": 2, "AVG(Price)": 199.0, "SUM(otherNum)": 1.6, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.8, "CategoryID": 2, "anotherID": "[NULL]", "SUM(Price)": 398, "COUNT(Price)": 2, "AVG(Price)": 199.0, "SUM(otherNum)": 1.6, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 2.0, "CategoryID": 3, "anotherID": 0, "SUM(Price)": 31.0, "COUNT(Price)": 1, "AVG(Price)": 31.0, "SUM(otherNum)": 2, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.1, "CategoryID": 3, "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 1.05, "CategoryID": 3, "anotherID": "[NULL]", "SUM(Price)": 45.0, "COUNT(Price)": 2, "AVG(Price)": 22.5, "SUM(otherNum)": 2.1, "SupplierID": 11, "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 2.0, "CategoryID": 3, "anotherID": 0, "SUM(Price)": 31.0, "COUNT(Price)": 1, "AVG(Price)": 31.0, "SUM(otherNum)": 2, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.1, "CategoryID": 3, "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 1.05, "CategoryID": 3, "anotherID": "[NULL]", "SUM(Price)": 45.0, "COUNT(Price)": 2, "AVG(Price)": 22.5, "SUM(otherNum)": 2.1, "SupplierID": "[NULL]", "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": 0, "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": "[NULL]", "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": 0, "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.7, "CategoryID": 4, "anotherID": "[NULL]", "SUM(Price)": 44, "COUNT(Price)": 1, "AVG(Price)": 44.0, "SUM(otherNum)": 0.7, "SupplierID": "[NULL]", "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.5666666666666667, "CategoryID": "[NULL]", "anotherID": 1, "SUM(Price)": 54, "COUNT(Price)": 3, "AVG(Price)": 18.0, "SUM(otherNum)": 1.7, "SupplierID": 1, "COUNT(otherNum)": 3}, + { "AVG(otherNum)": 0.5666666666666667, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 54, "COUNT(Price)": 3, "AVG(Price)": 18.0, "SUM(otherNum)": 1.7, "SupplierID": 1, "COUNT(otherNum)": 3}, + { "AVG(otherNum)": 1.35, "CategoryID": "[NULL]", "anotherID": 0, "SUM(Price)": 75.0, "COUNT(Price)": 2, "AVG(Price)": 37.5, "SUM(otherNum)": 2.7, "SupplierID": 11, "COUNT(otherNum)": 2}, + { "AVG(otherNum)": 0.1, "CategoryID": "[NULL]", "anotherID": 1, "SUM(Price)": 14.0, "COUNT(Price)": 1, "AVG(Price)": 14.0, "SUM(otherNum)": 0.1, "SupplierID": 11, "COUNT(otherNum)": 1}, + { "AVG(otherNum)": 0.9333333333333332, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 89.0, "COUNT(Price)": 3, "AVG(Price)": 29.666666666666668, "SUM(otherNum)": 2.8, "SupplierID": 11, "COUNT(otherNum)": 3}, + { "AVG(otherNum)": 0.8374999999999999, "CategoryID": "[NULL]", "anotherID": 0, "SUM(Price)": 545.0, "COUNT(Price)": 8, "AVG(Price)": 68.125, "SUM(otherNum)": 6.699999999999999, "SupplierID": "[NULL]", "COUNT(otherNum)": 8}, + { "AVG(otherNum)": 0.45, "CategoryID": "[NULL]", "anotherID": 1, "SUM(Price)": 68.0, "COUNT(Price)": 4, "AVG(Price)": 17.0, "SUM(otherNum)": 1.8, "SupplierID": "[NULL]", "COUNT(otherNum)": 4}, + { "AVG(otherNum)": 0.7083333333333331, "CategoryID": "[NULL]", "anotherID": "[NULL]", "SUM(Price)": 613.0, "COUNT(Price)": 12, "AVG(Price)": 51.083333333333336, "SUM(otherNum)": 8.499999999999998, "SupplierID": "[NULL]", "COUNT(otherNum)": 12} +] +---- +|=== \ No newline at end of file diff --git a/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/index.adoc b/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/index.adoc index 26d934a40e..86d44dd819 100644 --- a/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/index.adoc +++ b/docs/asciidoc/modules/ROOT/pages/overview/apoc.agg/index.adoc @@ -20,5 +20,13 @@ Returns index of the `element` that match the given `predicate` apoc.agg.multiStats(nodeOrRel, keys) - Return a multi-dimensional aggregation |label:function[] + + +|xref::overview/apoc.agg/apoc.agg.rollup.adoc[apoc.agg.rollup icon:book[]] + +apoc.agg.rollup(, [groupKeys], [aggKeys]) + +Emulate an Oracle/Mysql rollup command: `ROLLUP groupKeys, SUM(aggKey1), AVG(aggKey1), COUNT(aggKey1), SUM(aggKey2), AVG(aggKey2), ... ` +|label:function[] |=== diff --git a/docs/asciidoc/modules/ROOT/partials/generated-documentation/documentation.adoc b/docs/asciidoc/modules/ROOT/partials/generated-documentation/documentation.adoc index 303335081a..caa7558900 100644 --- a/docs/asciidoc/modules/ROOT/partials/generated-documentation/documentation.adoc +++ b/docs/asciidoc/modules/ROOT/partials/generated-documentation/documentation.adoc @@ -29,6 +29,13 @@ Returns index of the `element` that match the given `predicate` apoc.agg.multiStats(nodeOrRel, keys) - Return a multi-dimensional aggregation |label:procedure[] + +|xref::overview/apoc.agg/apoc.agg.rollup.adoc[apoc.agg.rollup icon:book[]] + +apoc.agg.rollup(, [groupKeys], [aggKeys]) + +Emulate an Oracle/Mysql rollup command: `ROLLUP groupKeys, SUM(aggKey1), AVG(aggKey1), COUNT(aggKey1), SUM(aggKey2), AVG(aggKey2), ... ` +|label:procedure[] |=== diff --git a/docs/asciidoc/modules/ROOT/partials/generated-documentation/nav.adoc b/docs/asciidoc/modules/ROOT/partials/generated-documentation/nav.adoc index 569d7b5424..049c457a71 100644 --- a/docs/asciidoc/modules/ROOT/partials/generated-documentation/nav.adoc +++ b/docs/asciidoc/modules/ROOT/partials/generated-documentation/nav.adoc @@ -6,6 +6,7 @@ This file is generated by DocsTest, so don't change it! *** xref::overview/apoc.agg/apoc.agg.row.adoc[] *** xref::overview/apoc.agg/apoc.agg.position.adoc[] *** xref::overview/apoc.agg/apoc.agg.multiStats.adoc[] +*** xref::overview/apoc.agg/apoc.agg.rollup.adoc[] ** xref::overview/apoc.bolt/index.adoc[] *** xref::overview/apoc.bolt/apoc.bolt.execute.adoc[] *** xref::overview/apoc.bolt/apoc.bolt.load.adoc[] diff --git a/docs/asciidoc/modules/ROOT/partials/usage/config/apoc.agg.rollup.adoc b/docs/asciidoc/modules/ROOT/partials/usage/config/apoc.agg.rollup.adoc new file mode 100644 index 0000000000..8a254f6300 --- /dev/null +++ b/docs/asciidoc/modules/ROOT/partials/usage/config/apoc.agg.rollup.adoc @@ -0,0 +1,9 @@ +The procedure support the following properties in the APOC configuration file (`apoc.conf`): + +.Config parameters +[opts=header, cols="1,1,1,3"] +|=== +| name | type | default | description +| cube | boolean | false| to emulate the https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32311[CUBE] clause, + instead of the https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32084[ROLLUP] one. +|=== \ No newline at end of file diff --git a/extended/src/main/java/apoc/agg/AggregationUtil.java b/extended/src/main/java/apoc/agg/AggregationUtil.java new file mode 100644 index 0000000000..450b6d4384 --- /dev/null +++ b/extended/src/main/java/apoc/agg/AggregationUtil.java @@ -0,0 +1,51 @@ +package apoc.agg; + +import java.util.Map; + +public class AggregationUtil { + + public static void updateAggregationValues(Map partialResult, Object property, String countKey, String sumKey, String avgKey) { + Number count = updateCountValue(partialResult, countKey); + + updateSumAndAvgValues(partialResult, property, count.doubleValue(), sumKey, avgKey); + } + + private static Number updateCountValue(Map partialResult, String countKey) { + Number count = partialResult.compute(countKey, + ((subKey, subVal) -> { + return subVal == null ? 1 : subVal.longValue() + 1; + })); + return count; + } + + private static void updateSumAndAvgValues(Map partialResult, Object property, double count, String sumKey, String avgKey) { + if (!(property instanceof Number)) { + return; + } + + Number numberProp = (Number) property; + + Number sum = partialResult.compute(sumKey, + ((subKey, subVal) -> { + if (subVal == null) { + if (numberProp instanceof Long longProp) { + return longProp; + } + return numberProp.doubleValue(); + } + if (subVal instanceof Long long1 + && numberProp instanceof Long long2) { + return long1 + long2; + } + return subVal.doubleValue() + numberProp.doubleValue(); + })); + + partialResult.compute(avgKey, ((subKey, subVal) -> { + if (subVal == null) { + return numberProp.doubleValue(); + } + return sum.doubleValue() / count; + }) + ); + } +} diff --git a/extended/src/main/java/apoc/agg/MultiStats.java b/extended/src/main/java/apoc/agg/MultiStats.java index 49ee004405..f078d45b32 100644 --- a/extended/src/main/java/apoc/agg/MultiStats.java +++ b/extended/src/main/java/apoc/agg/MultiStats.java @@ -13,6 +13,8 @@ import java.util.Map; import java.util.Objects; +import static apoc.agg.AggregationUtil.updateAggregationValues; + @Extended public class MultiStats { @@ -44,22 +46,11 @@ public void aggregate( Map propMap = Objects.requireNonNullElseGet(propVal, HashMap::new); - Number count = propMap.compute("count", - ((subKey, subVal) -> subVal == null ? 1 : subVal.longValue() + 1) ); + String countKey = "count"; + String sumKey = "sum"; + String avgKey = "avg"; - if (property instanceof Number numberProp) { - Number sum = propMap.compute("sum", - ((subKey, subVal) -> { - if (subVal == null) return numberProp; - if (subVal instanceof Long long1 && numberProp instanceof Long long2) { - return long1 + long2; - } - return subVal.doubleValue() + numberProp.doubleValue(); - })); - - propMap.compute("avg", - ((subKey, subVal) -> subVal == null ? numberProp.doubleValue() : sum.doubleValue() / count.doubleValue() )); - } + updateAggregationValues(propMap, property, countKey, sumKey, avgKey); return propMap; }); diff --git a/extended/src/main/java/apoc/agg/Rollup.java b/extended/src/main/java/apoc/agg/Rollup.java new file mode 100644 index 0000000000..63d4d0ff57 --- /dev/null +++ b/extended/src/main/java/apoc/agg/Rollup.java @@ -0,0 +1,194 @@ +package apoc.agg; + +import apoc.Extended; +import apoc.util.Util; +import org.apache.commons.collections4.ListUtils; +import org.neo4j.graphdb.Entity; +import org.neo4j.procedure.Description; +import org.neo4j.procedure.Name; +import org.neo4j.procedure.UserAggregationFunction; +import org.neo4j.procedure.UserAggregationResult; +import org.neo4j.procedure.UserAggregationUpdate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static apoc.agg.AggregationUtil.updateAggregationValues; + + +@Extended +public class Rollup { + public static final String NULL_ROLLUP = "[NULL]"; + + @UserAggregationFunction("apoc.agg.rollup") + @Description("apoc.agg.rollup(, [groupKeys], [aggKeys])" + + "\n Emulate an Oracle/Mysql rollup command: `ROLLUP groupKeys, SUM(aggKey1), AVG(aggKey1), COUNT(aggKey1), SUM(aggKey2), AVG(aggKey2), ... `") + public RollupFunction rollup() { + return new RollupFunction(); + } + + public static class RollupFunction { + // Function to generate all combinations of a list with "TEST" as a placeholder + public static List> generateCombinationsWithPlaceholder(List elements) { + List> result = new ArrayList<>(); + generateCombinationsWithPlaceholder(elements, 0, new ArrayList<>(), result); + return result; + } + + // Helper function for generating combinations recursively + private static void generateCombinationsWithPlaceholder(List elements, int index, List current, List> result) { + if (index == elements.size()) { + result.add(new ArrayList<>(current)); + return; + } + + current.add(elements.get(index)); + generateCombinationsWithPlaceholder(elements, index + 1, current, result); + current.remove(current.size() - 1); + + // Add "NULL" as a combination placeholder + current.add((T) NULL_ROLLUP); + generateCombinationsWithPlaceholder(elements, index + 1, current, result); + current.remove(current.size() - 1); + } + + private final Map result = new HashMap<>(); + + private final Map, Map> rolledUpData = new HashMap<>(); + private List groupKeysRes = null; + + @UserAggregationUpdate + public void aggregate( + @Name("value") Object value, + @Name(value = "groupKeys") List groupKeys, + @Name(value = "aggKeys") List aggKeys, + @Name(value = "config", defaultValue = "{}") Map config) { + + boolean cube = Util.toBoolean(config.get("cube")); + + Entity entity = (Entity) value; + + if (groupKeys.isEmpty()) { + return; + } + groupKeysRes = groupKeys; + + /* + if true: + emulate the CUBE command: https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32311 + else: + emulate the ROLLUP command: https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32084 + */ + if (cube) { + List> groupingSets = generateCombinationsWithPlaceholder(groupKeys); + + for (List groupKey : groupingSets) { + List partialKey = new ArrayList<>(); + for (String column : groupKey) { + partialKey.add(((Entity) value).getProperty(column, NULL_ROLLUP)); + } + if (!rolledUpData.containsKey(partialKey)) { + rolledUpData.put(partialKey, new HashMap<>()); + } + rollupAggregationProperties(aggKeys, entity, partialKey); + } + + return; + } + + List groupKey = groupKeys.stream() + .map(i -> entity.getProperty(i, null)) + .toList(); + + for (int i = 0; i <= groupKey.size(); i++) { + // add NULL_ROLLUP to remaining elements, + // e.g. `[, `NULL_ROLLUP`, `NULL_ROLLUP`]` + List partialKey = ListUtils.union(groupKey.subList(0, i), Collections.nCopies(groupKey.size() - i, NULL_ROLLUP)); + if (!rolledUpData.containsKey(partialKey)) { + rolledUpData.put(partialKey, new HashMap<>()); + } + rollupAggregationProperties(aggKeys, entity, partialKey); + } + } + + private void rollupAggregationProperties(List aggKeys, Entity entity, List partialKey) { + Map partialResult = rolledUpData.get(partialKey); + for(var aggKey: aggKeys) { + if (!entity.hasProperty(aggKey)) { + continue; + } + + Object property = entity.getProperty(aggKey); + + String countKey = "COUNT(%s)".formatted(aggKey); + String sumKey = "SUM(%s)".formatted(aggKey); + String avgKey = "AVG(%s)".formatted(aggKey); + + updateAggregationValues(partialResult, property, countKey, sumKey, avgKey); + } + } + + /** + * Transform a Map.of(ListGroupKeys, MapOfAggResults) in a List of Map.of(AggResult + ListGroupKeyToMap) + */ + @UserAggregationResult + public Object result() { + List> list = rolledUpData.entrySet().stream() + .map(e -> { + HashMap map = new HashMap<>(); + for (int i = 0; i < groupKeysRes.size(); i++) { + map.put(groupKeysRes.get(i), e.getKey().get(i)); + } + map.putAll(e.getValue()); + return map; + }) + .sorted((m1, m2) -> { + for (String key : groupKeysRes) { + Object value1 = m1.get(key); + Object value2 = m2.get(key); + int cmp = compareValues(value1, value2); + if (cmp != 0) { + return cmp; + } + } + return 0; + }) + .toList(); + + return list; + } + + /** + * We use this instead of e.g. apoc.coll.sortMulti + * since we have to handle the NULL_ROLLUP values as well + */ + private static int compareValues(Object value1, Object value2) { + if (value1 == null && value2 == null) { + return 0; + } else if (value1 == null) { + return 1; + } else if (value2 == null) { + return -1; + } else if (NULL_ROLLUP.equals(value1) && NULL_ROLLUP.equals(value2)) { + return 0; + } else if (NULL_ROLLUP.equals(value1)) { + return 1; + } else if (NULL_ROLLUP.equals(value2)) { + return -1; + } else if (value1 instanceof Comparable && value2 instanceof Comparable) { + try { + return ((Comparable) value1).compareTo(value2); + } catch (Exception e) { + // e.g. different data types, like int and strings + return 0; + } + + } else { + return 0; + } + } + } +} diff --git a/extended/src/main/resources/extended.txt b/extended/src/main/resources/extended.txt index 4eea7bc0d4..a3fac3bf46 100644 --- a/extended/src/main/resources/extended.txt +++ b/extended/src/main/resources/extended.txt @@ -1,6 +1,7 @@ apoc.agg.position apoc.agg.row apoc.agg.multiStats +apoc.agg.rollup apoc.algo.aStarWithPoint apoc.bolt.execute apoc.bolt.load diff --git a/extended/src/test/java/apoc/agg/RollupTest.java b/extended/src/test/java/apoc/agg/RollupTest.java new file mode 100644 index 0000000000..8b7079a0f1 --- /dev/null +++ b/extended/src/test/java/apoc/agg/RollupTest.java @@ -0,0 +1,165 @@ +package apoc.agg; + +import apoc.map.Maps; +import apoc.util.TestUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.neo4j.test.rule.DbmsRule; +import org.neo4j.test.rule.ImpermanentDbmsRule; + +import java.util.List; +import java.util.Map; + +import static apoc.agg.RollupTestUtil.*; +import static apoc.util.ExtendedTestUtil.assertMapEquals; +import static apoc.util.TestUtil.testCall; +import static apoc.util.Util.map; + + +public class RollupTest { + @ClassRule + public static DbmsRule db = new ImpermanentDbmsRule(); + + + @BeforeClass + public static void setUp() { + TestUtil.registerProcedure(db, Maps.class, Rollup.class); + + /* + + Similar to CREATE TABLE Products(SupplierID NUMBER(5,2), CategoryID NUMBER(5,2), Price NUMBER(5,2), otherNum FLOAT(5), anotherID NUMBER(5,2)); + + INSERT INTO Products VALUES(1, 1, 1, 18, 0.3); + INSERT INTO Products VALUES(1, 1, 0, 19, 0.5); + ... + */ + db.executeTransactionally(""" + CREATE (:Product {SupplierID: 1, CategoryID: 1, anotherID: 1, Price: 18, otherNum: 0.3}), + (:Product {SupplierID: 1, CategoryID: 1, anotherID: 0, Price: 19, otherNum: 0.5}), + (:Product {SupplierID: 1, CategoryID: 2, anotherID: 1, Price: 10, otherNum: 0.6}), + (:Product {SupplierID: 4, CategoryID: 8, anotherID: 0, Price: 31, otherNum: 0.6}), + (:Product {SupplierID: 5, CategoryID: 4, anotherID: 1, Price: 21, otherNum: 0.2}), + (:Product {SupplierID: 6, CategoryID: 8, anotherID: 1, Price: 6, otherNum: 0.5}), + (:Product {SupplierID: 6, CategoryID: 7, anotherID: 1, Price: 23, otherNum: 0.6}), + (:Product {SupplierID: 7, CategoryID: 3, anotherID: 1, Price: 17, otherNum: 0.7}), + (:Product {SupplierID: 7, CategoryID: 6, anotherID: 1, Price: 39, otherNum: 0.8}), + (:Product {SupplierID: 7, CategoryID: 8, anotherID: 1, Price: 63, otherNum: 0.9}), + (:Product {SupplierID: 8, CategoryID: 3, anotherID: 0, Price: 9, otherNum: 0.2}), + (:Product {SupplierID: 8, CategoryID: 3, anotherID: 1, Price: 81, otherNum: 0.5}), + (:Product {SupplierID: 9, CategoryID: 5, anotherID: 0, Price: 9, otherNum: 0.9}), + (:Product {SupplierID: 10, CategoryID: 1, anotherID: 1, Price: 5, otherNum: 0.2}), + (:Product {SupplierID: 11, CategoryID: 3, anotherID: 1, Price: 14.0, otherNum: 0.1}), + (:Product {SupplierID: 11, CategoryID: 3, anotherID: 0, Price: 31.0, otherNum: 2}), + (:Product {SupplierID: 11, CategoryID: 4, anotherID: 0, Price: 44, otherNum: 0.7}), + (:Product {SupplierID: 1, CategoryID: NULL, anotherID: 1, Price: 18, otherNum: 0.7}), + (:Product {SupplierID: NULL, CategoryID: NULL, anotherID: 0, Price: 18, otherNum: 0.6}), + (:Product {SupplierID: NULL, CategoryID: 2, anotherID: 0, Price: 199, otherNum: 0.8})"""); + } + + @AfterClass + public static void tearDown() { + db.shutdown(); + } + + // similar to https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32084 + // and MySql `WITH ROLLUP` command + @Test + public void testRollupRespectivelySupplierIDCategoryIDAndAnotherID() { + + List expected = getRollupTripleGroup(); + testCall(db, """ + MATCH (p:Product) + RETURN apoc.agg.rollup(p, $groupKeys, ["Price", "otherNum"]) as data + """, + map("groupKeys", List.of(SUPPLIER_ID, CATEGORY_ID, ANOTHER_ID)), + r -> { + assertRollupCommon(expected, r); + }); + } + + @Test + public void testRollupRespectivelyCategoryIDSupplierIDAndAnotherID() { + + List expected = getRollupTripleGroupTwo(); + testCall(db, """ + MATCH (p:Product) + RETURN apoc.agg.rollup(p, $groupKeys, ["Price", "otherNum"]) as data + """, + map("groupKeys", List.of(CATEGORY_ID, SUPPLIER_ID, ANOTHER_ID)), + r -> { + assertRollupCommon(expected, r); + }); + } + + @Test + public void testRollupWithSingleAggregationKey() { + + List expected = getRollupTripleGroupTwo() + .stream() + .peek(i -> { + i.remove(sumOtherNum); + i.remove(countOtherNum); + i.remove(avgOtherNum); + }) + .toList(); + testCall(db, """ + MATCH (p:Product) + RETURN apoc.agg.rollup(p, $groupKeys, ["Price"]) as data + """, + map("groupKeys", List.of(CATEGORY_ID, SUPPLIER_ID, ANOTHER_ID)), + r -> { + assertRollupCommon(expected, r); + }); + } + + // similar to https://docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/rollup_c.htm#32311 + @Test + public void testCubeRespectivelySupplierIDCategoryIDAndAnotherID() { + + List expected = getCubeTripleGroupTwo(); + testCall(db, """ + MATCH (p:Product) + RETURN apoc.agg.rollup(p, $groupKeys, ["Price", "otherNum"], {cube: true}) as data + + """, + map("groupKeys", List.of(CATEGORY_ID, SUPPLIER_ID, ANOTHER_ID)), + r -> { + assertRollupCommon(expected, r); + }); + } + + @Test + public void testCube2() { + + List expected = getCubeTripleGroupTwo() + .stream() + .peek(i -> { + i.remove(sumOtherNum); + i.remove(countOtherNum); + i.remove(avgOtherNum); + }) + .toList(); + testCall(db, """ + MATCH (p:Product) + RETURN apoc.agg.rollup(p, $groupKeys, ["Price"], {cube: true}) as data + + """, + map("groupKeys", List.of(CATEGORY_ID, SUPPLIER_ID, ANOTHER_ID)), + r -> { + assertRollupCommon(expected, r); + }); + } + + private void assertRollupCommon(List expected, Map r) { + List data = (List) r.get("data"); + + for (int i = 0; i < expected.size(); i++) { + assertMapEquals("Maps at index %s are not equal. \n Expected: %s, \n Actual: %s\n".formatted(i, expected.get(i), data.get(i)), + expected.get(i), + data.get(i) + ); + } + } +} diff --git a/extended/src/test/java/apoc/agg/RollupTestUtil.java b/extended/src/test/java/apoc/agg/RollupTestUtil.java new file mode 100644 index 0000000000..5bfce6b4a1 --- /dev/null +++ b/extended/src/test/java/apoc/agg/RollupTestUtil.java @@ -0,0 +1,551 @@ +package apoc.agg; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static apoc.agg.Rollup.NULL_ROLLUP; +import static apoc.util.MapUtil.map; + +public class RollupTestUtil { + public static final String CATEGORY_ID = "CategoryID"; + public static final String SUPPLIER_ID = "SupplierID"; + public static final String ANOTHER_ID = "anotherID"; + + public static final String sumOtherNum = "SUM(otherNum)"; + public static final String countOtherNum = "COUNT(otherNum)"; + public static final String avgOtherNum = "AVG(otherNum)"; + + public static final String sumPrice = "SUM(Price)"; + public static final String countPrice = "COUNT(Price)"; + public static final String avgPrice = "AVG(Price)"; + + static List getRollupTripleGroup() { + + return new ArrayList<>() {{ + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, 0L, + sumOtherNum, 0.5, countOtherNum, 1L, sumPrice, 19L, avgOtherNum, 0.5, countPrice, 1L, avgPrice, 19.0)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + sumOtherNum, 0.3, countOtherNum, 1L, sumPrice, 18L, avgOtherNum, 0.3, countPrice, 1L, avgPrice, 18.0)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.8, countOtherNum, 2L, sumPrice, 37L, avgOtherNum, 0.4, countPrice, 2L, avgPrice, 18.5)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 10L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 10.0)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 10L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 10.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 2.0999999999999996, countOtherNum, 4L, sumPrice, 65L, avgOtherNum, 0.5249999999999999, countPrice, 4L, avgPrice, 16.25)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + sumOtherNum, 0.7, countOtherNum, 1L, sumPrice, 18L, avgOtherNum, 0.7, countPrice, 1L, avgPrice, 18.0)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.7, countOtherNum, 1L, sumPrice, 18L, avgOtherNum, 0.7, countPrice, 1L, avgPrice, 18.0)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 4L, ANOTHER_ID, 0L, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 31L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 31.0)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 4L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 31L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 31.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 4L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 31L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 31.0)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 5L, ANOTHER_ID, 1L, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 21L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 21.0)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 5L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 21L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 21.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 5L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 21L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 21.0)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 23L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 23.0)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 23L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 23.0)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + sumOtherNum, 0.5, countOtherNum, 1L, sumPrice, 6L, avgOtherNum, 0.5, countPrice, 1L, avgPrice, 6.0)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.5, countOtherNum, 1L, sumPrice, 6L, avgOtherNum, 0.5, countPrice, 1L, avgPrice, 6.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 1.1, countOtherNum, 2L, sumPrice, 29L, avgOtherNum, 0.55, countPrice, 2L, avgPrice, 14.5)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + sumOtherNum, 0.7, countOtherNum, 1L, sumPrice, 17L, avgOtherNum, 0.7, countPrice, 1L, avgPrice, 17.0)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.7, countOtherNum, 1L, sumPrice, 17L, avgOtherNum, 0.7, countPrice, 1L, avgPrice, 17.0)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + sumOtherNum, 0.8, countOtherNum, 1L, sumPrice, 39L, avgOtherNum, 0.8, countPrice, 1L, avgPrice, 39.0)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.8, countOtherNum, 1L, sumPrice, 39L, avgOtherNum, 0.8, countPrice, 1L, avgPrice, 39.0)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + sumOtherNum, 0.9, countOtherNum, 1L, sumPrice, 63L, avgOtherNum, 0.9, countPrice, 1L, avgPrice, 63.0)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.9, countOtherNum, 1L, sumPrice, 63L, avgOtherNum, 0.9, countPrice, 1L, avgPrice, 63.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 2.4, countOtherNum, 3L, sumPrice, 119L, avgOtherNum, 0.7999999999999999, countPrice, 3L, avgPrice, 39.666666666666664)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, 0L, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 9L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 9.0)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, 1L, + sumOtherNum, 0.5, countOtherNum, 1L, sumPrice, 81L, avgOtherNum, 0.5, countPrice, 1L, avgPrice, 81.0)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.7, countOtherNum, 2L, sumPrice, 90L, avgOtherNum, 0.35, countPrice, 2L, avgPrice, 45.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 8L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.7, countOtherNum, 2L, sumPrice, 90L, avgOtherNum, 0.35, countPrice, 2L, avgPrice, 45.0)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, 9L, ANOTHER_ID, 0L, + sumOtherNum, 0.9, countOtherNum, 1L, sumPrice, 9L, avgOtherNum, 0.9, countPrice, 1L, avgPrice, 9.0)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, 9L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.9, countOtherNum, 1L, sumPrice, 9L, avgOtherNum, 0.9, countPrice, 1L, avgPrice, 9.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 9L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.9, countOtherNum, 1L, sumPrice, 9L, avgOtherNum, 0.9, countPrice, 1L, avgPrice, 9.0)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 10L, ANOTHER_ID, 1L, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 5L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 5.0)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 10L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 5L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 5.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 10L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.2, countOtherNum, 1L, sumPrice, 5L, avgOtherNum, 0.2, countPrice, 1L, avgPrice, 5.0)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + sumOtherNum, 2L, countOtherNum, 1L, sumPrice, 31.0, avgOtherNum, 2.0, countPrice, 1L, avgPrice, 31.0)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, 1L, + sumOtherNum, 0.1, countOtherNum, 1L, sumPrice, 14.0, avgOtherNum, 0.1, countPrice, 1L, avgPrice, 14.0)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 2.1, countOtherNum, 2L, sumPrice, 45.0, avgOtherNum, 1.05, countPrice, 2L, avgPrice, 22.5)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + sumOtherNum, 0.7, countOtherNum, 1L, sumPrice, 44L, avgOtherNum, 0.7, countPrice, 1L, avgPrice, 44.0)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.7, countOtherNum, 1L, sumPrice, 44L, avgOtherNum, 0.7, countPrice, 1L, avgPrice, 44.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 2.8, countOtherNum, 3L, sumPrice, 89.0, avgOtherNum, 0.9333333333333332, countPrice, 3L, avgPrice, 29.666666666666668)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 12.4, countOtherNum, 20L, sumPrice, 675.0, avgOtherNum, 0.62, countPrice, 20L, avgPrice, 33.75)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, null, ANOTHER_ID, 0L, + sumOtherNum, 0.8, countOtherNum, 1L, sumPrice, 199L, avgOtherNum, 0.8, countPrice, 1L, avgPrice, 199.0)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, null, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.8, countOtherNum, 1L, sumPrice, 199L, avgOtherNum, 0.8, countPrice, 1L, avgPrice, 199.0)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, null, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 1.4, countOtherNum, 2L, sumPrice, 217L, avgOtherNum, 0.7, countPrice, 2L, avgPrice, 108.5)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, null, ANOTHER_ID, 0L, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 18L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 18.0)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, null, ANOTHER_ID, NULL_ROLLUP, + sumOtherNum, 0.6, countOtherNum, 1L, sumPrice, 18L, avgOtherNum, 0.6, countPrice, 1L, avgPrice, 18.0)); + }}; + } + + static List getRollupTripleGroupTwo() { + return new ArrayList<>() {{ + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, 0L, + avgOtherNum, 0.5, sumPrice, 19L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 19.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + avgOtherNum, 0.3, sumPrice, 18L, countPrice, 1L, sumOtherNum, 0.3, avgPrice, 18.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.4, sumPrice, 37L, countPrice, 2L, sumOtherNum, 0.8, avgPrice, 18.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 10L, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 5L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 5.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 10L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.2, sumPrice, 5L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 5.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.3333333333333333, sumPrice, 42L, countPrice, 3L, sumOtherNum, 1.0, avgPrice, 14.0, countOtherNum, 3L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + avgOtherNum, 0.6, sumPrice, 10L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 10.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 10L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 10.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 209L, countPrice, 2L, sumOtherNum, 1.4, avgPrice, 104.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, null, ANOTHER_ID, 0L, + avgOtherNum, 0.8, sumPrice, 199L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 199.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, null, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.8, sumPrice, 199L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 199.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.7, sumPrice, 17L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 17.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 17L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 17.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, 0L, + avgOtherNum, 0.2, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, 1L, + avgOtherNum, 0.5, sumPrice, 81L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 81.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.35, sumPrice, 90L, countPrice, 2L, sumOtherNum, 0.7, avgPrice, 45.0, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + avgOtherNum, 2.0, sumPrice, 31.0, countPrice, 1L, sumOtherNum, 2L, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, 1L, + avgOtherNum, 0.1, sumPrice, 14.0, countPrice, 1L, sumOtherNum, 0.1, avgPrice, 14.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 1.05, sumPrice, 45.0, countPrice, 2L, sumOtherNum, 2.1, avgPrice, 22.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 152.0, countPrice, 5L, sumOtherNum, 3.5, avgPrice, 30.4, countOtherNum, 5L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 5L, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 5L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + avgOtherNum, 0.7, sumPrice, 44L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 44.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 44L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 44.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.44999999999999996, sumPrice, 65L, countPrice, 2L, sumOtherNum, 0.8999999999999999, avgPrice, 32.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, 9L, ANOTHER_ID, 0L, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, 9L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 4L, ANOTHER_ID, 0L, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 4L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + avgOtherNum, 0.5, sumPrice, 6L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 6.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.5, sumPrice, 6L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 6.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.9, sumPrice, 63L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 63.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 63L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 63.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6666666666666666, sumPrice, 100L, countPrice, 3L, sumOtherNum, 2.0, avgPrice, 33.333333333333336, countOtherNum, 3L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.62, sumPrice, 675.0, countPrice, 20L, sumOtherNum, 12.4, avgPrice, 33.75, countOtherNum, 20L)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + avgOtherNum, 0.7, sumPrice, 18L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 18.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 18L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 18.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6499999999999999, sumPrice, 36L, countPrice, 2L, sumOtherNum, 1.2999999999999998, avgPrice, 18.0, countOtherNum, 2L)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, null, ANOTHER_ID, 0L, + avgOtherNum, 0.6, sumPrice, 18L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 18.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, null, SUPPLIER_ID, null, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 18L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 18.0, countOtherNum, 1L)); + }}; + } + + static List getCubeTripleGroupTwo() { + return new ArrayList<>() {{ + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, 0L, + avgOtherNum, 0.5, sumPrice, 19L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 19.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + avgOtherNum, 0.3, sumPrice, 18L, countPrice, 1L, sumOtherNum, 0.3, avgPrice, 18.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.4, sumPrice, 37L, countPrice, 2L, sumOtherNum, 0.8, avgPrice, 18.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 10L, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 5L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 5.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, 10L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.2, sumPrice, 5L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 5.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 0.5, sumPrice, 19L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 19.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.25, sumPrice, 23L, countPrice, 2L, sumOtherNum, 0.5, avgPrice, 11.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 1L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.3333333333333333, sumPrice, 42L, countPrice, 3L, sumOtherNum, 1.0, avgPrice, 14.0, countOtherNum, 3L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + avgOtherNum, 0.6, sumPrice, 10L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 10.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 10L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 10.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 0.8, sumPrice, 398L, countPrice, 2L, sumOtherNum, 1.6, avgPrice, 199.0, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.6, sumPrice, 10L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 10.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 2L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7333333333333334, sumPrice, 408L, countPrice, 3L, sumOtherNum, 2.2, avgPrice, 136.0, countOtherNum, 3L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.7, sumPrice, 17L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 17.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 17L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 17.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, 0L, + avgOtherNum, 0.2, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, 1L, + avgOtherNum, 0.5, sumPrice, 81L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 81.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 8L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.35, sumPrice, 90L, countPrice, 2L, sumOtherNum, 0.7, avgPrice, 45.0, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + avgOtherNum, 2.0, sumPrice, 31.0, countPrice, 1L, sumOtherNum, 2L, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, 1L, + avgOtherNum, 0.1, sumPrice, 14.0, countPrice, 1L, sumOtherNum, 0.1, avgPrice, 14.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 1.05, sumPrice, 45.0, countPrice, 2L, sumOtherNum, 2.1, avgPrice, 22.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 1.1, sumPrice, 40.0, countPrice, 2L, sumOtherNum, 2.2, avgPrice, 20.0, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.43333333333333335, sumPrice, 112.0, countPrice, 3L, sumOtherNum, 1.3, avgPrice, 37.333333333333336, countOtherNum, 3L)); + add( + map(CATEGORY_ID, 3L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 152.0, countPrice, 5L, sumOtherNum, 3.5, avgPrice, 30.4, countOtherNum, 5L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 5L, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 5L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + avgOtherNum, 0.7, sumPrice, 44L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 44.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7, sumPrice, 44L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 44.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 0.7, sumPrice, 44L, countPrice, 1L, sumOtherNum, 0.7, avgPrice, 44.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 4L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.44999999999999996, sumPrice, 65L, countPrice, 2L, sumOtherNum, 0.8999999999999999, avgPrice, 32.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, 9L, ANOTHER_ID, 0L, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, 9L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 5L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 6L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.8, sumPrice, 39L, countPrice, 1L, sumOtherNum, 0.8, avgPrice, 39.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 7L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 23L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 23.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 4L, ANOTHER_ID, 0L, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 4L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + avgOtherNum, 0.5, sumPrice, 6L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 6.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.5, sumPrice, 6L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 6.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.9, sumPrice, 63L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 63.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 63L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 63.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.7, sumPrice, 69L, countPrice, 2L, sumOtherNum, 1.4, avgPrice, 34.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, 8L, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6666666666666666, sumPrice, 100L, countPrice, 3L, sumOtherNum, 2.0, avgPrice, 33.333333333333336, countOtherNum, 3L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 1L, ANOTHER_ID, 0L, + avgOtherNum, 0.5, sumPrice, 19L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 19.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 1L, ANOTHER_ID, 1L, + avgOtherNum, 0.575, sumPrice, 64L, countPrice, 4L, sumOtherNum, 2.3, avgPrice, 16.0, countOtherNum, 4L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 1L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.5599999999999999, sumPrice, 83L, countPrice, 5L, sumOtherNum, 2.8, avgPrice, 16.6, countOtherNum, 5L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 4L, ANOTHER_ID, 0L, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 4L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.6, sumPrice, 31L, countPrice, 1L, sumOtherNum, 0.6, avgPrice, 31.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 5L, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 5L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.2, sumPrice, 21L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 21.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 6L, ANOTHER_ID, 1L, + avgOtherNum, 0.55, sumPrice, 29L, countPrice, 2L, sumOtherNum, 1.1, avgPrice, 14.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 6L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.55, sumPrice, 29L, countPrice, 2L, sumOtherNum, 1.1, avgPrice, 14.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 7L, ANOTHER_ID, 1L, + avgOtherNum, 0.7999999999999999, sumPrice, 119L, countPrice, 3L, sumOtherNum, 2.4, avgPrice, 39.666666666666664, countOtherNum, 3L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 7L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.7999999999999999, sumPrice, 119L, countPrice, 3L, sumOtherNum, 2.4, avgPrice, 39.666666666666664, countOtherNum, 3L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 8L, ANOTHER_ID, 0L, + avgOtherNum, 0.2, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 8L, ANOTHER_ID, 1L, + avgOtherNum, 0.5, sumPrice, 81L, countPrice, 1L, sumOtherNum, 0.5, avgPrice, 81.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 8L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.35, sumPrice, 90L, countPrice, 2L, sumOtherNum, 0.7, avgPrice, 45.0, countOtherNum, 2L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 9L, ANOTHER_ID, 0L, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 9L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9, sumPrice, 9L, countPrice, 1L, sumOtherNum, 0.9, avgPrice, 9.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 10L, ANOTHER_ID, 1L, + avgOtherNum, 0.2, sumPrice, 5L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 5.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 10L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.2, sumPrice, 5L, countPrice, 1L, sumOtherNum, 0.2, avgPrice, 5.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 11L, ANOTHER_ID, 0L, + avgOtherNum, 1.35, sumPrice, 75.0, countPrice, 2L, sumOtherNum, 2.7, avgPrice, 37.5, countOtherNum, 2L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 11L, ANOTHER_ID, 1L, + avgOtherNum, 0.1, sumPrice, 14.0, countPrice, 1L, sumOtherNum, 0.1, avgPrice, 14.0, countOtherNum, 1L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, 11L, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.9333333333333332, sumPrice, 89.0, countPrice, 3L, sumOtherNum, 2.8, avgPrice, 29.666666666666668, countOtherNum, 3L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 0L, + avgOtherNum, 0.7416666666666667, sumPrice, 613.0, countPrice, 12L, sumOtherNum, 8.9, avgPrice, 51.083333333333336, countOtherNum, 12L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, 1L, + avgOtherNum, 0.5230769230769231, sumPrice, 333.0, countPrice, 13L, sumOtherNum, 6.8, avgPrice, 25.615384615384617, countOtherNum, 13L)); + add( + map(CATEGORY_ID, NULL_ROLLUP, SUPPLIER_ID, NULL_ROLLUP, ANOTHER_ID, NULL_ROLLUP, + avgOtherNum, 0.628, sumPrice, 946.0, countPrice, 25L, sumOtherNum, 15.7, avgPrice, 37.84, countOtherNum, 25L)); + }}; + } +} diff --git a/extended/src/test/java/apoc/util/ExtendedTestUtil.java b/extended/src/test/java/apoc/util/ExtendedTestUtil.java index 24777168c6..e956f706e9 100644 --- a/extended/src/test/java/apoc/util/ExtendedTestUtil.java +++ b/extended/src/test/java/apoc/util/ExtendedTestUtil.java @@ -18,16 +18,20 @@ public class ExtendedTestUtil { public static void assertMapEquals(Map expected, Map actual) { + assertMapEquals(null, expected, actual); + } + + public static void assertMapEquals(String errMsg, Map expected, Map actual) { if (expected == null) { assertNull(actual); } else { - assertEquals(expected.keySet(), actual.keySet()); + assertEquals(errMsg, expected.keySet(), actual.keySet()); actual.forEach((key, value) -> { if (value instanceof Map mapVal) { - assertMapEquals((Map) expected.get(key), mapVal); + assertMapEquals(errMsg, (Map) expected.get(key), mapVal); } else { - assertEquals(expected.get(key), value); + assertEquals(errMsg, expected.get(key), value); } }); }