Skip to content

Commit

Permalink
Fix: Silently chain transformers / loaders with the EtlBuilder (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpolaszek authored Nov 8, 2023
1 parent d373ccd commit 8095259
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 17 deletions.
36 changes: 28 additions & 8 deletions src/Internal/EtlBuilderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@
use Bentools\ETL\Extractor\CallableExtractor;
use Bentools\ETL\Extractor\ExtractorInterface;
use Bentools\ETL\Loader\CallableLoader;
use Bentools\ETL\Loader\ChainLoader;
use Bentools\ETL\Loader\LoaderInterface;
use Bentools\ETL\Recipe\Recipe;
use Bentools\ETL\Transformer\CallableTransformer;
use Bentools\ETL\Transformer\ChainTransformer;
use Bentools\ETL\Transformer\TransformerInterface;

use function count;

/**
* @internal
*
Expand All @@ -34,22 +38,38 @@ public function extractFrom(ExtractorInterface|callable $extractor): self
return $this->cloneWith(['extractor' => $extractor]);
}

public function transformWith(TransformerInterface|callable $transformer): self
public function transformWith(TransformerInterface|callable $transformer, TransformerInterface|callable ...$transformers): self
{
if (!$transformer instanceof TransformerInterface) {
$transformer = new CallableTransformer($transformer(...));
$transformers = [$transformer, ...$transformers];

foreach ($transformers as $t => $_transformer) {
if (!$_transformer instanceof TransformerInterface) {
$transformers[$t] = new CallableTransformer($_transformer(...));
}
}

if (count($transformers) > 1) {
return $this->cloneWith(['transformer' => new ChainTransformer(...$transformers)]);
}

return $this->cloneWith(['transformer' => $transformer]);
return $this->cloneWith(['transformer' => $transformers[0]]);
}

public function loadInto(LoaderInterface|callable $loader): self
public function loadInto(LoaderInterface|callable $loader, LoaderInterface|callable ...$loaders): self
{
if (!$loader instanceof LoaderInterface) {
$loader = new CallableLoader($loader(...));
$loaders = [$loader, ...$loaders];

foreach ($loaders as $l => $_loader) {
if (!$_loader instanceof LoaderInterface) {
$loaders[$l] = new CallableLoader($_loader(...));
}
}

if (count($loaders) > 1) {
return $this->cloneWith(['loader' => new ChainLoader(...$loaders)]);
}

return $this->cloneWith(['loader' => $loader]);
return $this->cloneWith(['loader' => $loaders[0]]);
}

public function withOptions(EtlConfiguration $configuration): self
Expand Down
10 changes: 6 additions & 4 deletions src/Loader/ChainLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
private array $loaders;

public function __construct(
LoaderInterface|callable ...$loaders
LoaderInterface|callable $loader,
LoaderInterface|callable ...$loaders,
) {
foreach ($loaders as $l => $loader) {
if (!$loader instanceof LoaderInterface) {
$loaders[$l] = new CallableLoader($loader(...));
$loaders = [$loader, ...$loaders];
foreach ($loaders as $l => $_loader) {
if (!$_loader instanceof LoaderInterface) {
$loaders[$l] = new CallableLoader($_loader(...));
}
}
$this->loaders = $loaders;
Expand Down
13 changes: 8 additions & 5 deletions src/Transformer/ChainTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
*/
private array $transformers;

public function __construct(TransformerInterface|callable ...$transformers)
{
foreach ($transformers as $t => $transformer) {
if (!$transformer instanceof TransformerInterface) {
$transformers[$t] = new CallableTransformer($transformer(...));
public function __construct(
TransformerInterface|callable $transformer,
TransformerInterface|callable ...$transformers
) {
$transformers = [$transformer, ...$transformers];
foreach ($transformers as $t => $_transformer) {
if (!$_transformer instanceof TransformerInterface) {
$transformers[$t] = new CallableTransformer($_transformer(...));
}
}
$this->transformers = $transformers;
Expand Down
20 changes: 20 additions & 0 deletions tests/Unit/Loader/ChainLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,23 @@ public function flush(bool $isPartial, EtlState $state): mixed
->and([...$b])->toBe(['foo', 'bar'])
->and([...$c])->toBe(['bar']);
});

it('silently chains loaders', function () {
// Background
$a = new ArrayObject();
$b = new ArrayObject();

// Given
$input = ['foo', 'bar'];
$executor = (new EtlExecutor())->loadInto(
fn (string $item) => $a[] = $item, // @phpstan-ignore-line
fn (string $item) => $b[] = $item, // @phpstan-ignore-line
);

// When
$executor->process($input);

// Then
expect([...$a])->toBe(['foo', 'bar'])
->and([...$b])->toBe(['foo', 'bar']);
});
25 changes: 25 additions & 0 deletions tests/Unit/Transformer/ChainTransformerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,28 @@ function (string $item): Generator {
'rab-RAB',
]);
});

it('silently chains transformers', function () {
// Given
$input = ['foo', 'bar'];

$etl = (new EtlExecutor())
->transformWith(
fn (string $item): string => strrev($item),
function (string $item): Generator {
yield $item;
yield strtoupper($item);
},
fn (Generator $items): array => [...$items],
fn (array $items): string => implode('-', $items)
);

// When
$report = $etl->process($input);

// Then
expect($report->output)->toBe([
'oof-OOF',
'rab-RAB',
]);
});

0 comments on commit 8095259

Please sign in to comment.