Skip to content

Commit 8183a28

Browse files
authored
Allow to group by more than one column on pivot (#1370)
* Allow to group by more than one column on pivot * Removed development leftovers * Removed development leftovers
1 parent 108b5fb commit 8183a28

File tree

3 files changed

+108
-20
lines changed

3 files changed

+108
-20
lines changed

src/core/etl/src/Flow/ETL/GroupBy.php

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,25 @@ public function group(Rows $rows) : void
6666

6767
$this->pivotColumns = \array_values(\array_filter(\array_unique($this->pivotColumns)));
6868

69-
$indexRef = $this->refs->first();
70-
7169
foreach ($rows as $row) {
72-
$indexValue = $row->valueOf($indexRef);
70+
$values = [];
71+
72+
foreach ($this->refs as $ref) {
73+
$values[$ref->name()] = $row->valueOf($ref);
74+
}
75+
76+
$indexValue = $this->hash($values);
77+
7378
$pivotValue = $row->valueOf($this->pivot);
7479

7580
if (!\array_key_exists($indexValue, $this->pivotedTable)) {
7681
$this->pivotedTable[$indexValue] = [];
7782
}
7883

84+
foreach ($this->refs as $ref) {
85+
$this->pivotedTable[$indexValue][$ref->name()] = $row->valueOf($ref);
86+
}
87+
7988
if ($pivotValue === null) {
8089
continue;
8190
}
@@ -124,10 +133,6 @@ public function group(Rows $rows) : void
124133

125134
public function pivot(Reference $ref) : void
126135
{
127-
if ($this->refs->count() !== 1) {
128-
throw new RuntimeException('Pivot requires exactly one entry reference in group by, given: ' . $this->refs->count() . '');
129-
}
130-
131136
$this->pivot = $ref;
132137
}
133138

@@ -140,7 +145,9 @@ public function result(FlowContext $context) : Rows
140145
$row = [$this->refs->first()->name() => $index];
141146

142147
foreach ($columns as $rowIndex => $values) {
143-
$row[$rowIndex] = $values->result()->value();
148+
$row[$rowIndex] = $values instanceof AggregatingFunction
149+
? $values->result()->value()
150+
: $values;
144151
}
145152

146153
foreach ($this->pivotColumns as $column) {

src/core/etl/tests/Flow/ETL/Tests/Integration/DataFrame/GroupByTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,98 @@ public function test_pivot() : void
386386
);
387387
}
388388

389+
public function test_pivot_with_multiple_group_by_column() : void
390+
{
391+
$dataset1 = [
392+
['date' => '2023-11-01', 'type' => 'admin', 'user' => 'norberttech', 'contributions' => 5],
393+
['date' => '2023-11-01', 'type' => 'contributor', 'user' => 'stloyd', 'contributions' => 4],
394+
['date' => '2023-11-02', 'type' => 'admin', 'user' => 'norberttech', 'contributions' => 3],
395+
['date' => '2023-11-02', 'type' => 'contributor', 'user' => 'stloyd', 'contributions' => 6],
396+
];
397+
398+
$dataset2 = [
399+
['date' => '2023-11-03', 'type' => 'admin', 'user' => 'norberttech', 'contributions' => 2],
400+
['date' => '2023-11-03', 'type' => 'contributor', 'user' => 'stloyd', 'contributions' => 7],
401+
['date' => '2023-11-04', 'type' => 'admin', 'user' => 'norberttech', 'contributions' => 3],
402+
['date' => '2023-11-04', 'type' => 'contributor', 'user' => 'stloyd', 'contributions' => 5],
403+
['date' => '2023-11-05', 'type' => 'admin', 'user' => 'norberttech', 'contributions' => 7],
404+
['date' => '2023-11-05', 'type' => 'contributor', 'user' => 'stloyd', 'contributions' => 11],
405+
];
406+
407+
$rows = df()
408+
->read(from_all(from_array($dataset1), from_array($dataset2)))
409+
->groupBy(ref('date'), ref('type'))
410+
->pivot(ref('user'))
411+
->aggregate(sum(ref('contributions')))
412+
->fetch();
413+
414+
self::assertSame(
415+
[
416+
[
417+
'date' => '2023-11-01',
418+
'type' => 'admin',
419+
'norberttech' => 5,
420+
'stloyd' => null,
421+
],
422+
[
423+
'date' => '2023-11-01',
424+
'type' => 'contributor',
425+
'stloyd' => 4,
426+
'norberttech' => null,
427+
],
428+
[
429+
'date' => '2023-11-02',
430+
'type' => 'admin',
431+
'norberttech' => 3,
432+
'stloyd' => null,
433+
],
434+
[
435+
'date' => '2023-11-02',
436+
'type' => 'contributor',
437+
'stloyd' => 6,
438+
'norberttech' => null,
439+
],
440+
[
441+
'date' => '2023-11-03',
442+
'type' => 'admin',
443+
'norberttech' => 2,
444+
'stloyd' => null,
445+
],
446+
[
447+
'date' => '2023-11-03',
448+
'type' => 'contributor',
449+
'stloyd' => 7,
450+
'norberttech' => null,
451+
],
452+
[
453+
'date' => '2023-11-04',
454+
'type' => 'admin',
455+
'norberttech' => 3,
456+
'stloyd' => null,
457+
],
458+
[
459+
'date' => '2023-11-04',
460+
'type' => 'contributor',
461+
'stloyd' => 5,
462+
'norberttech' => null,
463+
],
464+
[
465+
'date' => '2023-11-05',
466+
'type' => 'admin',
467+
'norberttech' => 7,
468+
'stloyd' => null,
469+
],
470+
[
471+
'date' => '2023-11-05',
472+
'type' => 'contributor',
473+
'stloyd' => 11,
474+
'norberttech' => null,
475+
],
476+
],
477+
$rows->toArray()
478+
);
479+
}
480+
389481
public function test_standalone_avg_aggregation() : void
390482
{
391483
$rows = df()

src/core/etl/tests/Flow/ETL/Tests/Unit/GroupByTest.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use function Flow\ETL\DSL\{config, flow_context};
88
use function Flow\ETL\DSL\{int_entry, null_entry, ref, row, rows, str_entry, sum};
9-
use Flow\ETL\Exception\{InvalidArgumentException, RuntimeException};
9+
use Flow\ETL\Exception\{InvalidArgumentException};
1010
use Flow\ETL\{GroupBy, Tests\FlowTestCase};
1111

1212
final class GroupByTest extends FlowTestCase
@@ -118,15 +118,4 @@ public function test_group_by_with_pivoting_with_null_pivot_column() : void
118118
$group->result(flow_context(config()))->sortBy(ref('product'))
119119
);
120120
}
121-
122-
public function test_pivot_with_more_than_one_group_by_entry() : void
123-
{
124-
$this->expectException(RuntimeException::class);
125-
$this->expectExceptionMessage('Pivot requires exactly one entry reference in group by, given: 2');
126-
127-
$group = (new GroupBy('type', 'id'));
128-
129-
$group->aggregate(sum(ref('id')));
130-
$group->pivot(ref('id'));
131-
}
132121
}

0 commit comments

Comments
 (0)