Skip to content

Commit

Permalink
List select function (#893)
Browse files Browse the repository at this point in the history
* List select function

* Added missing classes
  • Loading branch information
norberttech committed Dec 31, 2023
1 parent b4fdb76 commit a09e99f
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 93 deletions.
8 changes: 0 additions & 8 deletions src/core/etl/src/Flow/ETL/CLI/CLI.php

This file was deleted.

40 changes: 0 additions & 40 deletions src/core/etl/src/Flow/ETL/CLI/Input.php

This file was deleted.

8 changes: 7 additions & 1 deletion src/core/etl/src/Flow/ETL/DSL/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use Flow\ETL\Function\First;
use Flow\ETL\Function\Hash;
use Flow\ETL\Function\Last;
use Flow\ETL\Function\ListFunctions;
use Flow\ETL\Function\Literal;
use Flow\ETL\Function\Max;
use Flow\ETL\Function\Min;
Expand Down Expand Up @@ -485,11 +486,16 @@ function ref(string $entry) : EntryReference
return new EntryReference($entry);
}

function structure(string $entry) : StructureFunctions
function structure_ref(string $entry) : StructureFunctions
{
return ref($entry)->structure();
}

function list_ref(string $entry) : ListFunctions
{
return ref($entry)->list();
}

function refs(string|Reference ...$entries) : References
{
return new References(...$entries);
Expand Down
17 changes: 17 additions & 0 deletions src/core/etl/src/Flow/ETL/Function/ListFunctions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);

namespace Flow\ETL\Function;

use Flow\ETL\Row\Reference;

final class ListFunctions
{
public function __construct(private readonly Reference $ref)
{
}

public function select(Reference|string ...$refs) : ListSelect
{
return new ListSelect($this->ref, ...$refs);
}
}
53 changes: 53 additions & 0 deletions src/core/etl/src/Flow/ETL/Function/ListSelect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);

namespace Flow\ETL\Function;

use Flow\ETL\Row;
use Flow\ETL\Row\Entry\ListEntry;
use Flow\ETL\Row\EntryReference;
use Flow\ETL\Row\Reference;
use Flow\ETL\Row\References;

final class ListSelect implements ScalarFunction
{
private readonly Reference $ref;

private readonly References $refs;

public function __construct(
Reference|string $ref,
Reference|string ...$refs,
) {
$this->ref = EntryReference::init($ref);
$this->refs = References::init(...$refs);
}

public function eval(Row $row) : array|null
{
if (!$row->has($this->ref)) {
return null;
}

$list = $row->get($this->ref);

if (!$list instanceof ListEntry) {
return null;
}

$output = [];

foreach ($list->value() as $index => $element) {
$output[$index] = [];

foreach ($this->refs as $ref) {
if (\is_array($element) && \array_key_exists($ref->to(), $element)) {
$output[$index][$ref->name()] = $element[$ref->to()];
} else {
$output[$index][$ref->name()] = null;
}
}
}

return $output;
}
}
6 changes: 6 additions & 0 deletions src/core/etl/src/Flow/ETL/Row/EntryReference.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Flow\ETL\Row;

use Flow\ETL\Function\ListFunctions;
use Flow\ETL\Function\ScalarFunctionChain;
use Flow\ETL\Function\StructureFunctions;
use Flow\ETL\Row;
Expand Down Expand Up @@ -85,6 +86,11 @@ public function is(Reference $ref) : bool
return $this->name() === $ref->name();
}

public function list() : ListFunctions
{
return new ListFunctions($this);
}

public function name() : string
{
return $this->alias ?? $this->entry;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);

namespace Flow\ETL\Tests\Integration\Function;

use function Flow\ETL\DSL\df;
use function Flow\ETL\DSL\from_array;
use function Flow\ETL\DSL\list_ref;
use PHPUnit\Framework\TestCase;

final class ListSelectTest extends TestCase
{
public function test_selecting_properties_from_list() : void
{
$rows = df()
->read(
from_array([
['list' => [['id' => 1, 'name' => 'test'], ['id' => 2, 'name' => 'test2'], ['id' => 3, 'name' => 'test3']]],
['list' => [['id' => 4, 'name' => 'test4'], ['id' => 5, 'name' => 'test5'], ['id' => 6, 'name' => 'test6']]],
])
)
->withEntry('list', list_ref('list')->select('id'))
->fetch();

$this->assertEquals(
[
['list' => [['id' => 1], ['id' => 2], ['id' => 3]]],
['list' => [['id' => 4], ['id' => 5], ['id' => 6]]],
],
$rows->toArray()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use function Flow\ETL\DSL\df;
use function Flow\ETL\DSL\from_array;
use function Flow\ETL\DSL\structure;
use function Flow\ETL\DSL\structure_ref;
use PHPUnit\Framework\TestCase;

final class StructureSelectTest extends TestCase
Expand All @@ -30,7 +30,7 @@ public function test_structure_keep() : void
]
)
)
->withEntry('user', structure('user')->select('id', 'email', 'tags'))
->withEntry('user', structure_ref('user')->select('id', 'email', 'tags'))
->fetch();

$this->assertEquals(
Expand Down
41 changes: 0 additions & 41 deletions src/core/etl/tests/Flow/ETL/Tests/Unit/CLI/InputTest.php

This file was deleted.

121 changes: 121 additions & 0 deletions src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ListSelectTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php declare(strict_types=1);

namespace Flow\ETL\Tests\Unit\Function;

use function Flow\ETL\DSL\list_entry;
use function Flow\ETL\DSL\ref;
use function Flow\ETL\DSL\row;
use function Flow\ETL\DSL\struct_element;
use function Flow\ETL\DSL\struct_type;
use function Flow\ETL\DSL\type_int;
use function Flow\ETL\DSL\type_list;
use function Flow\ETL\DSL\type_string;
use Flow\ETL\Function\ListSelect;
use PHPUnit\Framework\TestCase;

final class ListSelectTest extends TestCase
{
public function test_selecting_non_existing_value_from_list_using_alias() : void
{
$list = row(
list_entry(
'list',
[
['id' => 1, 'name' => 'test'],
['id' => 2, 'name' => 'test2'],
['id' => 3, 'name' => 'test3'],
],
type_list(struct_type(
struct_element('id', type_int()),
struct_element('name', type_string()),
))
)
);

$this->assertEquals(
[
['id' => 1, 'mail' => null],
['id' => 2, 'mail' => null],
['id' => 3, 'mail' => null],
],
(new ListSelect(ref('list'), ref('id'), ref('mail')))->eval($list)
);
}

public function test_selecting_value_from_list() : void
{
$list = row(
list_entry(
'list',
[
['id' => 1, 'name' => 'test'],
['id' => 2, 'name' => 'test2'],
['id' => 3, 'name' => 'test3'],
],
type_list(struct_type(
struct_element('id', type_int()),
struct_element('name', type_string()),
))
)
);

$this->assertEquals(
[
['id' => 1],
['id' => 2],
['id' => 3],
],
(new ListSelect(ref('list'), 'id'))->eval($list)
);
}

public function test_selecting_value_from_list_using_alias() : void
{
$list = row(
list_entry(
'list',
[
['id' => 1, 'name' => 'test'],
['id' => 2, 'name' => 'test2'],
['id' => 3, 'name' => 'test3'],
],
type_list(struct_type(
struct_element('id', type_int()),
struct_element('name', type_string()),
))
)
);

$this->assertEquals(
[
['new_id' => 1],
['new_id' => 2],
['new_id' => 3],
],
(new ListSelect(ref('list'), ref('id')->as('new_id')))->eval($list)
);
}

public function test_selecting_value_from_simple_list() : void
{
$list = row(
list_entry(
'list',
[
'a', 'b', 'c', 'd',
],
type_list(type_string())
)
);

$this->assertEquals(
[
['id' => null],
['id' => null],
['id' => null],
['id' => null],
],
(new ListSelect(ref('list'), ref('id')))->eval($list)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Flow\ETL\Function\StructureSelect;
use PHPUnit\Framework\TestCase;

final class StructureKeepTest extends TestCase
final class StructureSelectTest extends TestCase
{
public function test_selecting_multiple_values_from_structure() : void
{
Expand Down

0 comments on commit a09e99f

Please sign in to comment.