diff --git a/src/core/etl/src/Flow/ETL/DSL/functions.php b/src/core/etl/src/Flow/ETL/DSL/functions.php index e3e22308a..5476cacac 100644 --- a/src/core/etl/src/Flow/ETL/DSL/functions.php +++ b/src/core/etl/src/Flow/ETL/DSL/functions.php @@ -14,8 +14,7 @@ use Flow\ETL\Function\ArraySort\Sort; use Flow\ETL\Function\Between\Boundary; use Flow\ETL\Function\StyleConverter\StringStyles; -use Flow\ETL\Function\{ - All, +use Flow\ETL\Function\{All, Any, ArrayGet, ArrayGetCollection, @@ -32,6 +31,7 @@ CallMethod, Capitalize, Cast, + Coalesce, Collect, CollectUnique, Combine, @@ -74,8 +74,7 @@ ToUpper, Ulid, Uuid, - When -}; + When}; use Flow\ETL\Loader\StreamLoader\Output; use Flow\ETL\Loader\{ArrayLoader, CallbackLoader, MemoryLoader, StreamLoader, TransformerLoader}; use Flow\ETL\Memory\Memory; @@ -834,6 +833,12 @@ function cast(mixed $value, ScalarFunction|string|Type $type) : Cast return new Cast($value, $type); } +#[DocumentationDSL(module: Module::CORE, type: DSLType::SCALAR_FUNCTION)] +function coalesce(ScalarFunction ...$values) : Coalesce +{ + return new Coalesce(...$values); +} + #[DocumentationDSL(module: Module::CORE, type: DSLType::AGGREGATING_FUNCTION)] function count(EntryReference $function) : Count { diff --git a/src/core/etl/src/Flow/ETL/Function/Coalesce.php b/src/core/etl/src/Flow/ETL/Function/Coalesce.php new file mode 100644 index 000000000..4a4af7836 --- /dev/null +++ b/src/core/etl/src/Flow/ETL/Function/Coalesce.php @@ -0,0 +1,38 @@ + $values + */ + private array $values; + + public function __construct( + ScalarFunction ...$values, + ) { + $this->values = $values; + } + + public function eval(Row $row) : mixed + { + foreach ($this->values as $value) { + try { + $result = (new Parameter($value))->eval($row); + } catch (\Exception $e) { + continue; + } + + if ($result !== null) { + return $result; + } + } + + return null; + } +} diff --git a/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php b/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php index e78e31a25..74b2b1357 100644 --- a/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php +++ b/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php @@ -76,6 +76,11 @@ public function cast(ScalarFunction|string|Type $type) : self return new Cast($this, $type); } + public function coalesce(ScalarFunction ...$params) : self + { + return new Coalesce($this, ...$params); + } + public function concat(ScalarFunction|string ...$params) : self { return new Concat($this, ...$params); diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CoalesceTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CoalesceTest.php new file mode 100644 index 000000000..e0ed94d17 --- /dev/null +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CoalesceTest.php @@ -0,0 +1,35 @@ +eval(row(int_entry('id', 1))) + ); + } + + public function test_coalesce_on_lit_and_non_existing_entries() : void + { + self::assertSame( + 'N/A', + coalesce(ref('non_existing'), ref('string'), lit('N/A'))->eval(row(int_entry('id', 1))) + ); + } + + public function test_coalesce_on_ref() : void + { + self::assertSame( + 1, + ref('name')->coalesce(ref('id'), lit('N/A'))->eval(row(int_entry('id', 1))) + ); + } +}