Skip to content

Commit

Permalink
Feat: Instantiators (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpolaszek authored Nov 11, 2023
1 parent c0998ed commit eb16e95
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 31 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,27 @@ $progressBar = $output->createProgressBar();
$executor = (new EtlExecutor())->withRecipe(new ProgressBarRecipe($progressBar));
```

Instantiators
-------------

You can use the `extractFrom()`, `transformWith()`, `loadInto()` and `withRecipe()` functions
to instantiate an `EtlExecutor`.

Example:

```php
use BenTools\ETL\Recipe\LoggerRecipe;
use Monolog\Logger;

use function BenTools\ETL\withRecipe;

$logger = new Logger();
$report = withRecipe(new LoggerRecipe($logger))
->transformWith(fn ($value) => strtoupper($value))
->process(['foo', 'bar']);
```


Contribute
----------

Expand Down
11 changes: 7 additions & 4 deletions src/Internal/EtlBuilderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,15 @@ public function withOptions(EtlConfiguration $configuration): self
return $this->cloneWith(['options' => $configuration]);
}

public function withRecipe(Recipe|callable $recipe): self
public function withRecipe(Recipe|callable $recipe, Recipe|callable ...$recipes): self
{
if (!$recipe instanceof Recipe) {
$recipe = Recipe::fromCallable($recipe);
foreach ([$recipe, ...$recipes] as $_recipe) {
if (!$_recipe instanceof Recipe) {
$_recipe = Recipe::fromCallable($_recipe);
}
$executor = $_recipe->decorate($this);
}

return $recipe->decorate($this);
return $executor;
}
}
25 changes: 25 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@

namespace BenTools\ETL;

use BenTools\ETL\Extractor\ExtractorInterface;
use BenTools\ETL\Internal\Ref;
use BenTools\ETL\Loader\LoaderInterface;
use BenTools\ETL\Recipe\Recipe;
use BenTools\ETL\Transformer\TransformerInterface;

use function array_fill_keys;
use function array_intersect_key;
use function array_replace;
use function func_get_args;

/**
* @internal
Expand Down Expand Up @@ -54,3 +59,23 @@ function unref(Ref $ref): mixed
{
return $ref->value;
}

function extractFrom(ExtractorInterface|callable $extractor, ExtractorInterface|callable ...$extractors): EtlExecutor
{
return (new EtlExecutor())->extractFrom(...func_get_args());
}

function transformWith(TransformerInterface|callable $transformer, TransformerInterface|callable ...$transformers): EtlExecutor
{
return (new EtlExecutor())->transformWith(...func_get_args());
}

function loadInto(LoaderInterface|callable $loader, LoaderInterface|callable ...$loaders): EtlExecutor
{
return (new EtlExecutor())->loadInto(...func_get_args());
}

function withRecipe(Recipe|callable $recipe): EtlExecutor
{
return (new EtlExecutor())->withRecipe(...func_get_args());
}
19 changes: 9 additions & 10 deletions tests/Behavior/LoadExceptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

namespace BenTools\ETL\Tests\Behavior;

use BenTools\ETL\EtlExecutor;
use BenTools\ETL\Exception\LoadException;
use RuntimeException;

use function BenTools\ETL\loadInto;
use function expect;
use function it;

it('throws a load exception when it is thrown from the extractor', function () {
$items = ['foo', 'bar', 'baz'];
$executor = (new EtlExecutor())->loadInto(function (mixed $value) {
$executor = loadInto(function (mixed $value) {
if ('bar' === $value) {
throw new LoadException('Cannot load `bar`.');
}
Expand All @@ -23,7 +23,7 @@

it('throws a load exception when some other exception is thrown', function () {
$items = ['foo', 'bar', 'baz'];
$executor = (new EtlExecutor())->loadInto(function (mixed $value) {
$executor = loadInto(function (mixed $value) {
if ('bar' === $value) {
throw new RuntimeException('Cannot load `bar`.');
}
Expand All @@ -34,13 +34,12 @@
it('has stopped processing items, but has loaded the previous ones', function () {
$items = ['foo', 'bar', 'baz'];
$loadedItems = [];
$executor = (new EtlExecutor())
->loadInto(function (mixed $value) use (&$loadedItems) {
if ('bar' === $value) {
throw new LoadException('Cannot load `bar`.');
}
$loadedItems[] = $value;
})
$executor = loadInto(function (mixed $value) use (&$loadedItems) {
if ('bar' === $value) {
throw new LoadException('Cannot load `bar`.');
}
$loadedItems[] = $value;
})
;
try {
$executor->process($items);
Expand Down
19 changes: 9 additions & 10 deletions tests/Behavior/TransformExceptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

namespace BenTools\ETL\Tests\Behavior;

use BenTools\ETL\EtlExecutor;
use BenTools\ETL\Exception\TransformException;
use RuntimeException;

use function BenTools\ETL\transformWith;
use function expect;
use function it;

it('throws an extract exception when it is thrown from the extractor', function () {
$items = ['foo', 'bar', 'baz'];
$executor = (new EtlExecutor())->transformWith(function (mixed $value) {
$executor = transformWith(function (mixed $value) {
if ('bar' === $value) {
throw new TransformException('Cannot transform `bar`.');
}
Expand All @@ -24,7 +24,7 @@

it('throws a transform exception when some other exception is thrown', function () {
$items = ['foo', 'bar', 'baz'];
$executor = (new EtlExecutor())->transformWith(function (mixed $value) {
$executor = transformWith(function (mixed $value) {
if ('bar' === $value) {
throw new RuntimeException('Cannot transform `bar`.');
}
Expand All @@ -36,13 +36,12 @@
it('has stopped processing items, but has loaded the previous ones', function () {
$items = ['foo', 'bar', 'baz'];
$loadedItems = [];
$executor = (new EtlExecutor())
->transformWith(function (mixed $value) {
if ('bar' === $value) {
throw new TransformException('Cannot transform `bar`.');
}
yield $value;
})
$executor = transformWith(function (mixed $value) {
if ('bar' === $value) {
throw new TransformException('Cannot transform `bar`.');
}
yield $value;
})
->loadInto(function (mixed $value) use (&$loadedItems) {
$loadedItems[] = $value;
})
Expand Down
12 changes: 6 additions & 6 deletions tests/Unit/Extractor/ChainExtractorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use BenTools\ETL\EtlExecutor;
use BenTools\ETL\Extractor\ChainExtractor;

use function BenTools\ETL\extractFrom;
use function expect;

it('chains extractors', function () {
Expand All @@ -26,12 +27,11 @@

it('silently chains extractors', function () {
// Given
$executor = (new EtlExecutor())
->extractFrom(
fn () => 'banana',
fn () => yield from ['apple', 'strawberry'],
fn () => ['raspberry', 'peach']
);
$executor = extractFrom(
fn () => 'banana',
fn () => yield from ['apple', 'strawberry'],
fn () => ['raspberry', 'peach']
);

// When
$report = $executor->process();
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Recipe/RecipeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@

use BenTools\ETL\EtlExecutor;

use function BenTools\ETL\withRecipe;
use function expect;

it('uses a recipe', function () {
// Given
$hasReceivedInitEvent = false;
$hasReceivedEndEvent = false;
$executor = (new EtlExecutor())->withRecipe(
$executor = withRecipe(
function (EtlExecutor $executor) use (&$hasReceivedInitEvent, &$hasReceivedEndEvent) {
return $executor
->onInit(function () use (&$hasReceivedInitEvent) {
Expand Down

0 comments on commit eb16e95

Please sign in to comment.