diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml index 6444efda8..66a76b8b1 100644 --- a/.github/workflows/publish-website.yml +++ b/.github/workflows/publish-website.yml @@ -30,7 +30,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib - name: "Get Composer Cache Directory" id: composer-cache diff --git a/.github/workflows/static-analyze.yml b/.github/workflows/static-analyze.yml index 635c3ebcb..44510c415 100644 --- a/.github/workflows/static-analyze.yml +++ b/.github/workflows/static-analyze.yml @@ -48,7 +48,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib - name: "Create cache directories" run: | diff --git a/.github/workflows/test-benchmark.yml b/.github/workflows/test-benchmark.yml index e1b1445c2..bf5983ede 100644 --- a/.github/workflows/test-benchmark.yml +++ b/.github/workflows/test-benchmark.yml @@ -43,7 +43,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib - name: "Get Composer Cache Directory" id: composer-cache diff --git a/.github/workflows/test-extensions.yml b/.github/workflows/test-extensions.yml index 2afb500c7..9a7efee17 100644 --- a/.github/workflows/test-extensions.yml +++ b/.github/workflows/test-extensions.yml @@ -54,7 +54,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr, brotli, lz4, zstd, snappy-https://github.com/kjdev/php-ext-snappy@0.2.1 + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib, brotli, lz4, zstd, snappy-https://github.com/kjdev/php-ext-snappy@0.2.1 env: SNAPPY_CONFIGURE_PREFIX_OPTS: "CXXFLAGS=-std=c++11" diff --git a/.github/workflows/test-mutations.yml b/.github/workflows/test-mutations.yml index 71cf4ef81..53fd2a6ea 100644 --- a/.github/workflows/test-mutations.yml +++ b/.github/workflows/test-mutations.yml @@ -47,7 +47,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib - name: "Get Composer Cache Directory" id: composer-cache diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index c44a8aca5..79d126878 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -92,7 +92,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib - name: "List PHP Extensions" run: php -m diff --git a/.github/workflows/test-website.yml b/.github/workflows/test-website.yml index d529fe30e..c447c32bd 100644 --- a/.github/workflows/test-website.yml +++ b/.github/workflows/test-website.yml @@ -41,7 +41,7 @@ jobs: tools: composer:v2 php-version: "${{ matrix.php-version }}" ini-values: memory_limit=-1 - extensions: :psr + extensions: :psr, bcmath, dom, hash, json, mbstring, xml, xmlwriter, xmlreader, zlib - name: "Get Composer Cache Directory" id: composer-cache diff --git a/composer.json b/composer.json index a2d12f929..516bf5ae4 100644 --- a/composer.json +++ b/composer.json @@ -16,9 +16,9 @@ "ext-hash": "*", "ext-json": "*", "ext-mbstring": "*", + "ext-xml": "*", "ext-xmlreader": "*", "ext-xmlwriter": "*", - "ext-xml": "*", "ext-zlib": "*", "composer-runtime-api": "^2.1", "coduo/php-humanizer": "^5.0", @@ -42,7 +42,6 @@ "aeon-php/calendar": "^1.0", "fakerphp/faker": "^1.23", "fig/log-test": "^1.1", - "moneyphp/money": "^4", "nyholm/psr7": "^1.8", "php-http/curl-client": "^2.2", "php-http/mock-client": "^1.5", diff --git a/composer.lock b/composer.lock index 390977a92..355673262 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "df6d65352e9c0ae8a899db350f07be33", + "content-hash": "6616bdd2a44ce8c33fadc7cd3c5a32f8", "packages": [ { "name": "aeon-php/calendar", @@ -3277,94 +3277,6 @@ }, "time": "2022-10-18T05:33:27+00:00" }, - { - "name": "moneyphp/money", - "version": "v4.5.0", - "source": { - "type": "git", - "url": "https://github.com/moneyphp/money.git", - "reference": "a1daa7daf159b4044e3d0c34c41fe2be5860e850" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/moneyphp/money/zipball/a1daa7daf159b4044e3d0c34c41fe2be5860e850", - "reference": "a1daa7daf159b4044e3d0c34c41fe2be5860e850", - "shasum": "" - }, - "require": { - "ext-bcmath": "*", - "ext-filter": "*", - "ext-json": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" - }, - "require-dev": { - "cache/taggable-cache": "^1.1.0", - "doctrine/coding-standard": "^12.0", - "doctrine/instantiator": "^1.5.0 || ^2.0", - "ext-gmp": "*", - "ext-intl": "*", - "florianv/exchanger": "^2.8.1", - "florianv/swap": "^4.3.0", - "moneyphp/crypto-currencies": "^1.1.0", - "moneyphp/iso-currencies": "^3.4", - "php-http/message": "^1.16.0", - "php-http/mock-client": "^1.6.0", - "phpbench/phpbench": "^1.2.5", - "phpunit/phpunit": "^10.5.9", - "psalm/plugin-phpunit": "^0.18.4", - "psr/cache": "^1.0.1 || ^2.0 || ^3.0", - "vimeo/psalm": "~5.20.0" - }, - "suggest": { - "ext-gmp": "Calculate without integer limits", - "ext-intl": "Format Money objects with intl", - "florianv/exchanger": "Exchange rates library for PHP", - "florianv/swap": "Exchange rates library for PHP", - "psr/cache-implementation": "Used for Currency caching" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Money\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mathias Verraes", - "email": "mathias@verraes.net", - "homepage": "http://verraes.net" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - }, - { - "name": "Frederik Bosch", - "email": "f.bosch@genkgo.nl" - } - ], - "description": "PHP implementation of Fowler's Money pattern", - "homepage": "http://moneyphp.org", - "keywords": [ - "Value Object", - "money", - "vo" - ], - "support": { - "issues": "https://github.com/moneyphp/money/issues", - "source": "https://github.com/moneyphp/money/tree/v4.5.0" - }, - "time": "2024-02-15T19:47:21+00:00" - }, { "name": "nyholm/psr7", "version": "1.8.1", diff --git a/src/adapter/etl-adapter-xml/composer.json b/src/adapter/etl-adapter-xml/composer.json index 6ca29d1d6..701a2de48 100644 --- a/src/adapter/etl-adapter-xml/composer.json +++ b/src/adapter/etl-adapter-xml/composer.json @@ -13,9 +13,9 @@ "require": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "ext-dom": "*", - "ext-xmlreader": "*", "ext-xml": "*", - "ext-writer": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", "flow-php/etl": "^0.8 || 1.x-dev" }, "config": { diff --git a/src/core/etl/composer.json b/src/core/etl/composer.json index 4c4ae6e4a..a38e6d9ff 100644 --- a/src/core/etl/composer.json +++ b/src/core/etl/composer.json @@ -16,11 +16,10 @@ "flow-php/rdsl": "^0.8 || 1.x-dev", "flow-php/filesystem": "^0.8 || 1.x-dev", "psr/simple-cache": "^1.0 || ^2.0 || ^3.0", - "webmozart/glob": "^3.0 || ^4.0" + "webmozart/glob": "^3.0 || ^4.0", + "jawira/case-converter": "^3.4" }, "require-dev": { - "jawira/case-converter": "^3.4", - "moneyphp/money": "^4", "ramsey/uuid": "^4.5", "symfony/uid": "^6.3 || ^7.0" }, @@ -28,11 +27,6 @@ "optimize-autoloader": true, "sort-packages": true }, - "suggest": { - "jawira/case-converter": "Provides CaseConverter that is required by the EntryNameCaseConverterTransformer", - "moneyphp/money": "Provides MoneyParser that is required by ToMoney scalar function", - "ramsey/uuid": "Provides scalar function `uuid_v4` and `uuid_v7` that allow generate uuid entry" - }, "license": "MIT", "autoload": { "files": [ diff --git a/src/core/etl/src/Flow/ETL/DSL/functions.php b/src/core/etl/src/Flow/ETL/DSL/functions.php index 54ece2ccf..eea7190c6 100644 --- a/src/core/etl/src/Flow/ETL/DSL/functions.php +++ b/src/core/etl/src/Flow/ETL/DSL/functions.php @@ -17,13 +17,13 @@ use Flow\ETL\Function\{ All, Any, - ArrayExists, ArrayGet, ArrayGetCollection, ArrayKeyRename, ArrayKeysStyleConvert, ArrayMerge, ArrayMergeCollection, + ArrayPathExists, ArrayReverse, ArraySort, ArrayUnpack, @@ -70,7 +70,6 @@ ToDate, ToDateTime, ToLower, - ToMoney, ToTimeZone, ToUpper, Ulid, @@ -568,17 +567,17 @@ function exists(ScalarFunction $ref) : Exists return new Exists($ref); } -function when(ScalarFunction $ref, ScalarFunction $then, ?ScalarFunction $else = null) : When +function when(mixed $condition, mixed $then, mixed $else = null) : When { - return new When($ref, $then, $else); + return new When($condition, $then, $else); } -function array_get(ScalarFunction $ref, string $path) : ArrayGet +function array_get(ScalarFunction $ref, ScalarFunction|string $path) : ArrayGet { return new ArrayGet($ref, $path); } -function array_get_collection(ScalarFunction $ref, string ...$keys) : ArrayGetCollection +function array_get_collection(ScalarFunction $ref, ScalarFunction|array $keys) : ArrayGetCollection { return new ArrayGetCollection($ref, $keys); } @@ -588,22 +587,22 @@ function array_get_collection_first(ScalarFunction $ref, string ...$keys) : Arra return ArrayGetCollection::fromFirst($ref, $keys); } -function array_exists(ScalarFunction $ref, string $path) : ArrayExists +function array_exists(ScalarFunction|array $ref, ScalarFunction|string $path) : ArrayPathExists { - return new ArrayExists($ref, $path); + return new ArrayPathExists($ref, $path); } -function array_merge(ScalarFunction $left, ScalarFunction $right) : ArrayMerge +function array_merge(ScalarFunction|array $left, ScalarFunction|array $right) : ArrayMerge { return new ArrayMerge($left, $right); } -function array_merge_collection(ScalarFunction $ref) : ArrayMergeCollection +function array_merge_collection(ScalarFunction|array $array) : ArrayMergeCollection { - return new ArrayMergeCollection($ref); + return new ArrayMergeCollection($array); } -function array_key_rename(ScalarFunction $ref, string $path, string $newName) : ArrayKeyRename +function array_key_rename(ScalarFunction $ref, ScalarFunction|string $path, ScalarFunction|string $newName) : ArrayKeyRename { return new ArrayKeyRename($ref, $path, $newName); } @@ -613,12 +612,16 @@ function array_keys_style_convert(ScalarFunction $ref, StringStyles|string $styl return new ArrayKeysStyleConvert($ref, $style instanceof StringStyles ? $style : StringStyles::fromString($style)); } -function array_sort(ScalarFunction $function, ?string $sort_function = null, ?int $flags = null, bool $recursive = true) : ArraySort +function array_sort(ScalarFunction $function, ScalarFunction|Sort|null $sort_function = null, ScalarFunction|int|null $flags = null, ScalarFunction|bool $recursive = true) : ArraySort { - return new ArraySort($function, $sort_function ? Sort::fromString($sort_function) : Sort::sort, $flags, $recursive); + if ($sort_function === null) { + $sort_function = Sort::sort; + } + + return new ArraySort($function, $sort_function, $flags, $recursive); } -function array_reverse(ScalarFunction $function, bool $preserveKeys = false) : ArrayReverse +function array_reverse(ScalarFunction|array $function, ScalarFunction|bool $preserveKeys = false) : ArrayReverse { return new ArrayReverse($function, $preserveKeys); } @@ -628,17 +631,17 @@ function now(\DateTimeZone $time_zone = new \DateTimeZone('UTC')) : Now return new Now($time_zone); } -function between(ScalarFunction $ref, ScalarFunction $lowerBound, ScalarFunction $upperBound, Boundary $boundary = Boundary::LEFT_INCLUSIVE) : Between +function between(mixed $value, mixed $lower_bound, mixed $upper_bound, ScalarFunction|Boundary $boundary = Boundary::LEFT_INCLUSIVE) : Between { - return new Between($ref, $lowerBound, $upperBound, $boundary); + return new Between($value, $lower_bound, $upper_bound, $boundary); } -function to_date_time(ScalarFunction $ref, string $format = 'Y-m-d H:i:s', \DateTimeZone $timeZone = new \DateTimeZone('UTC')) : ToDateTime +function to_date_time(mixed $ref, ScalarFunction|string $format = 'Y-m-d H:i:s', ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC')) : ToDateTime { return new ToDateTime($ref, $format, $timeZone); } -function to_date(ScalarFunction $ref, string $format = 'Y-m-d', \DateTimeZone $timeZone = new \DateTimeZone('UTC')) : ToDate +function to_date(mixed $ref, ScalarFunction|string $format = 'Y-m-d', ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC')) : ToDate { return new ToDate($ref, $format, $timeZone); } @@ -648,29 +651,29 @@ function date_time_format(ScalarFunction $ref, string $format) : DateTimeFormat return new DateTimeFormat($ref, $format); } -function split(ScalarFunction $ref, ScalarFunction|string $separator, ScalarFunction|int $limit = PHP_INT_MAX) : Split +function split(ScalarFunction|string $value, ScalarFunction|string $separator, ScalarFunction|int $limit = PHP_INT_MAX) : Split { - return new Split($ref, $separator, $limit); + return new Split($value, $separator, $limit); } -function combine(ScalarFunction $keys, ScalarFunction $values) : Combine +function combine(ScalarFunction|array $keys, ScalarFunction|array $values) : Combine { return new Combine($keys, $values); } -function concat(ScalarFunction ...$functions) : Concat +function concat(ScalarFunction|string ...$functions) : Concat { return new Concat(...$functions); } -function hash(ScalarFunction $function, Algorithm $algorithm = new NativePHPHash()) : Hash +function hash(mixed $value, Algorithm $algorithm = new NativePHPHash()) : Hash { - return new Hash($function, $algorithm); + return new Hash($value, $algorithm); } -function cast(ScalarFunction $function, string|Type $type) : Cast +function cast(mixed $value, ScalarFunction|string|Type $type) : Cast { - return new Cast($function, $type); + return new Cast($value, $type); } function count(Reference $function) : Count @@ -697,9 +700,9 @@ function count(Reference $function) : Count * | 2| | | 4| 5| 6| * +--+-----+-----+-----+-----+-----+ */ -function array_unpack(ScalarFunction $function, array $skip_keys = [], ?string $entry_prefix = null) : ArrayUnpack +function array_unpack(ScalarFunction|array $array, ScalarFunction|array $skip_keys = [], ScalarFunction|string|null $entry_prefix = null) : ArrayUnpack { - return new ArrayUnpack($function, $skip_keys, $entry_prefix); + return new ArrayUnpack($array, $skip_keys, $entry_prefix); } /** @@ -727,9 +730,9 @@ function array_expand(ScalarFunction $function, ArrayExpand $expand = ArrayExpan return new \Flow\ETL\Function\ArrayExpand($function, $expand); } -function size(ScalarFunction $function) : Size +function size(mixed $value) : Size { - return new Size($function); + return new Size($value); } function uuid_v4() : Uuid @@ -737,34 +740,37 @@ function uuid_v4() : Uuid return Uuid::uuid4(); } -function uuid_v7(?ScalarFunction $function = null) : Uuid +function uuid_v7(ScalarFunction|\DateTimeInterface|null $value = null) : Uuid { - return Uuid::uuid7($function); + return Uuid::uuid7($value); } -function ulid(?ScalarFunction $function = null) : Ulid +function ulid(ScalarFunction|string|null $value = null) : Ulid { - return new Ulid($function); + return new Ulid($value); } -function lower(ScalarFunction $function) : ToLower +function lower(ScalarFunction|string $value) : ToLower { - return new ToLower($function); + return new ToLower($value); } -function capitalize(ScalarFunction $function) : Capitalize +function capitalize(ScalarFunction|string $value) : Capitalize { - return new Capitalize($function); + return new Capitalize($value); } -function upper(ScalarFunction $function) : ToUpper +function upper(ScalarFunction|string $value) : ToUpper { - return new ToUpper($function); + return new ToUpper($value); } -function call_method(ScalarFunction $object, ScalarFunction $method, ScalarFunction ...$params) : CallMethod +/** + * @param array $params + */ +function call_method(object $object, ScalarFunction|string $method, array $params = []) : CallMethod { - return new CallMethod($object, $method, ...$params); + return new CallMethod($object, $method, $params); } function all(ScalarFunction ...$functions) : All @@ -772,19 +778,19 @@ function all(ScalarFunction ...$functions) : All return new All(...$functions); } -function any(ScalarFunction ...$functions) : Any +function any(ScalarFunction ...$values) : Any { - return new Any(...$functions); + return new Any(...$values); } -function not(ScalarFunction $function) : Not +function not(ScalarFunction $value) : Not { - return new Not($function); + return new Not($value); } -function to_timezone(ScalarFunction $function, ScalarFunction $timeZone) : ToTimeZone +function to_timezone(ScalarFunction|\DateTimeInterface $value, ScalarFunction|\DateTimeZone|string $timeZone) : ToTimeZone { - return new ToTimeZone($function, $timeZone); + return new ToTimeZone($value, $timeZone); } function ignore_error_handler() : IgnoreError @@ -802,75 +808,49 @@ function throw_error_handler() : ThrowError return new ThrowError(); } -function to_money(ScalarFunction $amount, ScalarFunction $currency, ?\Money\MoneyParser $moneyParser = null) : ToMoney -{ - if (null !== $moneyParser) { - return new ToMoney($amount, $currency, $moneyParser); - } - - return new ToMoney($amount, $currency); -} - -function regex_replace(ScalarFunction $pattern, ScalarFunction $replacement, ScalarFunction $subject, ?ScalarFunction $limit = null) : RegexReplace +function regex_replace(ScalarFunction|string $pattern, ScalarFunction|string $replacement, ScalarFunction|string $subject, ScalarFunction|int|null $limit = null) : RegexReplace { return new RegexReplace($pattern, $replacement, $subject, $limit); } -function regex_match_all(ScalarFunction $pattern, ScalarFunction $subject, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : RegexMatchAll +function regex_match_all(ScalarFunction|string $pattern, ScalarFunction|string $subject, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : RegexMatchAll { return new RegexMatchAll($pattern, $subject, $flags, $offset); } -function regex_match(ScalarFunction $pattern, ScalarFunction $subject, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : RegexMatch +function regex_match(ScalarFunction|string $pattern, ScalarFunction|string $subject, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : RegexMatch { return new RegexMatch($pattern, $subject, $flags, $offset); } -function regex(ScalarFunction $pattern, ScalarFunction $subject, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : Regex +function regex(ScalarFunction|string $pattern, ScalarFunction|string $subject, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : Regex { return new Regex($pattern, $subject, $flags, $offset); } -function regex_all(ScalarFunction $pattern, ScalarFunction $subject, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : RegexAll +function regex_all(ScalarFunction|string $pattern, ScalarFunction|string $subject, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : RegexAll { return new RegexAll($pattern, $subject, $flags, $offset); } -function sprintf(ScalarFunction $format, ScalarFunction ...$args) : Sprintf +function sprintf(ScalarFunction|string $format, ScalarFunction|float|int|string|null ...$args) : Sprintf { return new Sprintf($format, ...$args); } -function sanitize(ScalarFunction $function, ?ScalarFunction $placeholder = null, ?ScalarFunction $skipCharacters = null) : Sanitize +function sanitize(ScalarFunction|string $value, ScalarFunction|string $placeholder = '*', ScalarFunction|int|null $skipCharacters = null) : Sanitize { - return new Sanitize($function, $placeholder ?: new Literal('*'), $skipCharacters ?: new Literal(0)); + return new Sanitize($value, $placeholder, $skipCharacters); } -/** - * @param ScalarFunction $function - * @param null|ScalarFunction $precision - * @param int<0, max> $mode - */ -function round(ScalarFunction $function, ?ScalarFunction $precision = null, int $mode = PHP_ROUND_HALF_UP) : Round +function round(ScalarFunction|int|float $value, ScalarFunction|int $precision = 2, ScalarFunction|int $mode = PHP_ROUND_HALF_UP) : Round { - return new Round($function, $precision ?? lit(2), $mode); + return new Round($value, $precision, $mode); } -function number_format(ScalarFunction $function, ?ScalarFunction $decimals = null, ?ScalarFunction $decimalSeparator = null, ?ScalarFunction $thousandsSeparator = null) : NumberFormat +function number_format(ScalarFunction|int|float $value, ScalarFunction|int $decimals = 2, ScalarFunction|string $decimal_separator = '.', ScalarFunction|string $thousands_separator = ',') : NumberFormat { - if ($decimals === null) { - $decimals = lit(0); - } - - if ($decimalSeparator === null) { - $decimalSeparator = lit('.'); - } - - if ($thousandsSeparator === null) { - $thousandsSeparator = lit(','); - } - - return new NumberFormat($function, $decimals, $decimalSeparator, $thousandsSeparator); + return new NumberFormat($value, $decimals, $decimal_separator, $thousands_separator); } /** diff --git a/src/core/etl/src/Flow/ETL/Function/Any.php b/src/core/etl/src/Flow/ETL/Function/Any.php index 083d54019..79825323c 100644 --- a/src/core/etl/src/Flow/ETL/Function/Any.php +++ b/src/core/etl/src/Flow/ETL/Function/Any.php @@ -14,9 +14,9 @@ final class Any extends ScalarFunctionChain implements CompositeScalarFunction private readonly array $refs; public function __construct( - ScalarFunction ...$refs, + ScalarFunction ...$values, ) { - $this->refs = $refs; + $this->refs = $values; } public function eval(Row $row) : mixed diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayExpand.php b/src/core/etl/src/Flow/ETL/Function/ArrayExpand.php index 2a67c3350..66b572c2c 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayExpand.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayExpand.php @@ -15,9 +15,9 @@ public function __construct(private readonly ScalarFunction $ref, private readon public function eval(Row $row) : mixed { - $array = $this->ref->eval($row); + $array = (new Parameter($this->ref))->asArray($row); - if (!\is_array($array)) { + if ($array === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayGet.php b/src/core/etl/src/Flow/ETL/Function/ArrayGet.php index fa6ff97ff..f814db448 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayGet.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayGet.php @@ -12,21 +12,21 @@ final class ArrayGet extends ScalarFunctionChain { public function __construct( private readonly ScalarFunction $ref, - private readonly string $path + private readonly ScalarFunction|string $path ) { } public function eval(Row $row) : mixed { try { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->ref))->asArray($row); + $path = (new Parameter($this->path))->asString($row); - if (!\is_array($value)) { + if ($value === null || $path === null) { return null; } - return array_dot_get($value, $this->path); + return array_dot_get($value, $path); } catch (InvalidArgumentException $e) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayGetCollection.php b/src/core/etl/src/Flow/ETL/Function/ArrayGetCollection.php index f17f31613..bed79066c 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayGetCollection.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayGetCollection.php @@ -13,15 +13,15 @@ final class ArrayGetCollection extends ScalarFunctionChain { public function __construct( private readonly ScalarFunction $ref, - private readonly array $keys, - private readonly string $index = '*', + private readonly ScalarFunction|array $keys, + private readonly ScalarFunction|string $index = '*', ) { } /** * @param array $keys */ - public static function fromFirst(ScalarFunction $ref, array $keys) : self + public static function fromFirst(ScalarFunction $ref, ScalarFunction|array $keys) : self { return new self($ref, $keys, '0'); } @@ -29,17 +29,18 @@ public static function fromFirst(ScalarFunction $ref, array $keys) : self public function eval(Row $row) : mixed { try { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->ref))->asArray($row); + $index = (new Parameter($this->index))->asString($row); + $keys = (new Parameter($this->keys))->asArray($row); - if (!\is_array($value)) { + if ($value === null || $index === null || $keys === null) { return null; } - $path = \sprintf("{$this->index}.{%s}", \implode(',', \array_map(fn (string $entryName) : string => '?' . $entryName, $this->keys))); + $path = \sprintf("{$index}.{%s}", \implode(',', \array_map(fn (string $entryName) : string => '?' . $entryName, $keys))); try { - $array = ($this->index === '0') ? \array_values($value) : $value; + $array = ($index === '0') ? \array_values($value) : $value; $extractedValues = array_dot_get($array, $path); } catch (InvalidPathException) { diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayKeyRename.php b/src/core/etl/src/Flow/ETL/Function/ArrayKeyRename.php index aeb95921e..818f274ff 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayKeyRename.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayKeyRename.php @@ -11,20 +11,21 @@ final class ArrayKeyRename extends ScalarFunctionChain { public function __construct( private readonly ScalarFunction $ref, - private readonly string $path, - private readonly string $newName + private readonly ScalarFunction|string $path, + private readonly ScalarFunction|string $newName ) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->ref))->asArray($row); + $path = (new Parameter($this->path))->asString($row); + $newName = (new Parameter($this->newName))->asString($row); - if (!\is_array($value)) { + if ($value === null || $path === null || $newName === null) { return null; } - return array_dot_rename($value, $this->path, $this->newName); + return array_dot_rename($value, $path, $newName); } } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayKeysStyleConvert.php b/src/core/etl/src/Flow/ETL/Function/ArrayKeysStyleConvert.php index 19bfc3326..701eef233 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayKeysStyleConvert.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayKeysStyleConvert.php @@ -18,9 +18,9 @@ public function __construct( public function eval(Row $row) : mixed { - $array = $this->ref->eval($row); + $array = (new Parameter($this->ref))->asArray($row); - if (!\is_array($array)) { + if ($array === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayMerge.php b/src/core/etl/src/Flow/ETL/Function/ArrayMerge.php index 889fc93c6..752b27be5 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayMerge.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayMerge.php @@ -11,16 +11,16 @@ */ final class ArrayMerge extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $left, private readonly ScalarFunction $right) + public function __construct(private readonly ScalarFunction|array $left, private readonly ScalarFunction|array $right) { } public function eval(Row $row) : mixed { - $left = $this->left->eval($row); - $right = $this->right->eval($row); + $left = (new Parameter($this->left))->asArray($row); + $right = (new Parameter($this->right))->asArray($row); - if (!\is_array($left) || !\is_array($right)) { + if ($left === null || $right === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayMergeCollection.php b/src/core/etl/src/Flow/ETL/Function/ArrayMergeCollection.php index da6aaa4ed..5f7b2ae78 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayMergeCollection.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayMergeCollection.php @@ -8,25 +8,24 @@ final class ArrayMergeCollection extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref) + public function __construct(private readonly ScalarFunction|array $array) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $array = (new Parameter($this->array))->asArray($row); - if (!\is_array($value)) { + if ($array === null) { return null; } - foreach ($value as $element) { + foreach ($array as $element) { if (!\is_array($element)) { return null; } } - return \array_merge(...\array_values($value)); + return \array_merge(...\array_values($array)); } } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayExists.php b/src/core/etl/src/Flow/ETL/Function/ArrayPathExists.php similarity index 51% rename from src/core/etl/src/Flow/ETL/Function/ArrayExists.php rename to src/core/etl/src/Flow/ETL/Function/ArrayPathExists.php index 3de24662f..1f5b16c96 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayExists.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayPathExists.php @@ -8,25 +8,25 @@ use Flow\ETL\Exception\InvalidArgumentException; use Flow\ETL\Row; -final class ArrayExists extends ScalarFunctionChain +final class ArrayPathExists extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly string $path + private readonly ScalarFunction|array $array, + private readonly ScalarFunction|string $path ) { } public function eval(Row $row) : bool { try { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $array = (new Parameter($this->array))->asArray($row); + $path = (new Parameter($this->path))->asString($row); - if (!\is_array($value)) { + if ($array === null || $path === null) { return false; } - return array_dot_exists($value, $this->path); + return array_dot_exists($array, $path); } catch (InvalidArgumentException $e) { return false; } diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayReverse.php b/src/core/etl/src/Flow/ETL/Function/ArrayReverse.php index 51c22e1c2..7e553e1b5 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayReverse.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayReverse.php @@ -8,18 +8,19 @@ final class ArrayReverse extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $left, private readonly bool $preserveKeys) + public function __construct(private readonly ScalarFunction|array $array, private readonly ScalarFunction|bool $preserveKeys) { } public function eval(Row $row) : mixed { - $left = $this->left->eval($row); + $array = (new Parameter($this->array))->asArray($row); + $preserveKeys = (new Parameter($this->preserveKeys))->asBoolean($row); - if (!\is_array($left)) { + if ($array === null) { return null; } - return \array_reverse($left, $this->preserveKeys); + return \array_reverse($array, $preserveKeys); } } diff --git a/src/core/etl/src/Flow/ETL/Function/ArraySort.php b/src/core/etl/src/Flow/ETL/Function/ArraySort.php index 2633a69f5..ccde4695d 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArraySort.php +++ b/src/core/etl/src/Flow/ETL/Function/ArraySort.php @@ -11,24 +11,26 @@ final class ArraySort extends ScalarFunctionChain { public function __construct( private readonly ScalarFunction $ref, - private readonly Sort $function, - private readonly ?int $flags, - private readonly bool $recursive + private readonly ScalarFunction|Sort $sortFunction, + private readonly ScalarFunction|int|null $flags, + private readonly ScalarFunction|bool $recursive ) { } public function eval(Row $row) : mixed { - /** @var mixed $val */ - $val = $this->ref->eval($row); + $array = (new Parameter($this->ref))->asArray($row); + $flags = (new Parameter($this->flags))->asInt($row); + $recursive = (new Parameter($this->recursive))->asBoolean($row); + $sortFunction = (new Parameter($this->sortFunction))->asEnum($row, Sort::class); - if (!\is_array($val)) { + if ($array === null || $sortFunction === null) { return null; } - $this->recursiveSort($val, $this->function->value, $this->flags, $this->recursive); + $this->recursiveSort($array, $sortFunction->value, $flags, $recursive); - return $val; + return $array; } private function recursiveSort(array &$array, callable $function, ?int $flags, bool $recursive) : void diff --git a/src/core/etl/src/Flow/ETL/Function/ArrayUnpack.php b/src/core/etl/src/Flow/ETL/Function/ArrayUnpack.php index 4c38c0827..1ae32cb5d 100644 --- a/src/core/etl/src/Flow/ETL/Function/ArrayUnpack.php +++ b/src/core/etl/src/Flow/ETL/Function/ArrayUnpack.php @@ -9,17 +9,19 @@ final class ArrayUnpack extends ScalarFunctionChain implements ScalarFunction\UnpackResults { public function __construct( - private readonly ScalarFunction $ref, - private readonly array $skipKeys = [], - private readonly ?string $entryPrefix = null + private readonly ScalarFunction|array $array, + private readonly ScalarFunction|array $skipKeys = [], + private readonly ScalarFunction|string|null $entryPrefix = null ) { } public function eval(Row $row) : mixed { - $array = $this->ref->eval($row); + $array = (new Parameter($this->array))->asArray($row); + $skipKeys = (new Parameter($this->skipKeys))->asArray($row); + $entryPrefix = (new Parameter($this->entryPrefix))->asString($row); - if (!\is_array($array)) { + if ($array === null || $skipKeys === null) { return null; } @@ -32,12 +34,12 @@ public function eval(Row $row) : mixed foreach ($array as $key => $value) { $entryName = (string) $key; - if (\in_array($entryName, $this->skipKeys, true)) { + if (\in_array($entryName, $skipKeys, true)) { continue; } - if ($this->entryPrefix) { - $entryName = $this->entryPrefix . $entryName; + if ($entryName) { + $entryName = $entryPrefix . $entryName; } $values[$entryName] = $value; diff --git a/src/core/etl/src/Flow/ETL/Function/Between.php b/src/core/etl/src/Flow/ETL/Function/Between.php index 1c93192e9..02773e5bc 100644 --- a/src/core/etl/src/Flow/ETL/Function/Between.php +++ b/src/core/etl/src/Flow/ETL/Function/Between.php @@ -10,19 +10,24 @@ final class Between extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly ScalarFunction $lowerBoundRef, - private readonly ScalarFunction $upperBoundRef, - private readonly Boundary $boundary = Boundary::LEFT_INCLUSIVE, + private readonly mixed $value, + private readonly mixed $lowerBoundRef, + private readonly mixed $upperBoundRef, + private readonly ScalarFunction|Boundary $boundary = Boundary::LEFT_INCLUSIVE, ) { } public function eval(Row $row) : mixed { - $value = $this->ref->eval($row); - $lowerBound = $this->lowerBoundRef->eval($row); - $upperBound = $this->upperBoundRef->eval($row); + $value = (new Parameter($this->value))->eval($row); + $lowerBound = (new Parameter($this->lowerBoundRef))->eval($row); + $upperBound = (new Parameter($this->upperBoundRef))->eval($row); + $boundary = (new Parameter($this->boundary))->asEnum($row, Boundary::class); - return $this->boundary->compare($value, $lowerBound, $upperBound); + if (!$boundary instanceof Boundary) { + return null; + } + + return $boundary->compare($value, $lowerBound, $upperBound); } } diff --git a/src/core/etl/src/Flow/ETL/Function/CallMethod.php b/src/core/etl/src/Flow/ETL/Function/CallMethod.php index a8dea0cda..c51515ed8 100644 --- a/src/core/etl/src/Flow/ETL/Function/CallMethod.php +++ b/src/core/etl/src/Flow/ETL/Function/CallMethod.php @@ -9,25 +9,25 @@ final class CallMethod extends ScalarFunctionChain { /** - * @var ScalarFunction[] + * @param object $object + * @param ScalarFunction|string $method + * @param array $params */ - private readonly array $params; - - public function __construct(private readonly ScalarFunction $object, private readonly ScalarFunction $method, ScalarFunction ...$params) - { - $this->params = $params; + public function __construct( + private readonly object $object, + private readonly ScalarFunction|string $method, + private readonly array $params = [] + ) { } public function eval(Row $row) : mixed { - /** @var ?object $object */ - $object = $this->object->eval($row); - /** @var ?string $method */ - $method = $this->method->eval($row); + $object = (new Parameter($this->object))->asObject($row); + $method = (new Parameter($this->method))->asString($row); if (\is_object($object) && \is_string($method) && \method_exists($object, $method)) { return $object->{$method}(...\array_map( - static fn (ScalarFunction $param) : mixed => $param->eval($row), + static fn (mixed $param) : mixed => (new Parameter($param))->eval($row), $this->params )); } diff --git a/src/core/etl/src/Flow/ETL/Function/Capitalize.php b/src/core/etl/src/Flow/ETL/Function/Capitalize.php index e5270b07d..6e39f7ad2 100644 --- a/src/core/etl/src/Flow/ETL/Function/Capitalize.php +++ b/src/core/etl/src/Flow/ETL/Function/Capitalize.php @@ -8,22 +8,22 @@ final class Capitalize extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref) + public function __construct(private readonly ScalarFunction|string $string) { } public function eval(Row $row) : mixed { - $val = $this->ref->eval($row); + $string = (new Parameter($this->string))->eval($row); - if (!\is_string($val)) { + if ($string === null) { return null; } if (\function_exists('mb_convert_case')) { - return \mb_convert_case($val, \MB_CASE_TITLE); + return \mb_convert_case($string, \MB_CASE_TITLE); } - return \ucwords($val); + return \ucwords($string); } } diff --git a/src/core/etl/src/Flow/ETL/Function/Cast.php b/src/core/etl/src/Flow/ETL/Function/Cast.php index d5b978da5..9deeb0f81 100644 --- a/src/core/etl/src/Flow/ETL/Function/Cast.php +++ b/src/core/etl/src/Flow/ETL/Function/Cast.php @@ -12,8 +12,8 @@ final class Cast extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly string|Type $type + private readonly mixed $value, + private readonly ScalarFunction|Type|string $type ) { } @@ -23,9 +23,10 @@ public function __construct( */ public function eval(Row $row) : mixed { - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->eval($row); + $type = $this->type instanceof ScalarFunction ? (new Parameter($this->type))->asString($row) : $this->type; - if (null === $value) { + if (null === $value || $type === null) { return null; } @@ -37,6 +38,7 @@ public function eval(Row $row) : mixed return $caster->to($type)->value($value); } + /** @var string $type */ try { return match (\mb_strtolower($type)) { 'datetime' => $caster->to(type_datetime())->value($value), diff --git a/src/core/etl/src/Flow/ETL/Function/Combine.php b/src/core/etl/src/Flow/ETL/Function/Combine.php index 1381a034b..3c8c7dabc 100644 --- a/src/core/etl/src/Flow/ETL/Function/Combine.php +++ b/src/core/etl/src/Flow/ETL/Function/Combine.php @@ -9,17 +9,17 @@ final class Combine extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $keys, - private readonly ScalarFunction $values, + private readonly ScalarFunction|array $keys, + private readonly ScalarFunction|array $values, ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : ?array { - $keys = $this->keys->eval($row); - $values = $this->values->eval($row); + $keys = (new Parameter($this->keys))->asArray($row); + $values = (new Parameter($this->values))->asArray($row); - if (!\is_array($keys) || !\is_array($values)) { + if (null === $keys || null === $values) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/Comparison/Comparable.php b/src/core/etl/src/Flow/ETL/Function/Comparison/Comparable.php index 75e27b7b6..9290cc7e6 100644 --- a/src/core/etl/src/Flow/ETL/Function/Comparison/Comparable.php +++ b/src/core/etl/src/Flow/ETL/Function/Comparison/Comparable.php @@ -9,11 +9,11 @@ trait Comparable { - public function assertComparable(mixed $base, mixed $next, string $symbol) : void + public function assertComparable(mixed $left, mixed $right, string $symbol) : void { $detector = new TypeDetector(); - $baseType = $detector->detectType($base); - $nextType = $detector->detectType($next); + $baseType = $detector->detectType($left); + $nextType = $detector->detectType($right); if (!$baseType->isComparableWith($nextType)) { throw new InvalidArgumentException(\sprintf("Can't compare '(%s %s %s)' due to data type mismatch.", $baseType->toString(), $symbol, $nextType->toString())); diff --git a/src/core/etl/src/Flow/ETL/Function/Concat.php b/src/core/etl/src/Flow/ETL/Function/Concat.php index 89eec0737..655cdab8a 100644 --- a/src/core/etl/src/Flow/ETL/Function/Concat.php +++ b/src/core/etl/src/Flow/ETL/Function/Concat.php @@ -11,20 +11,20 @@ final class Concat extends ScalarFunctionChain { /** - * @var array + * @var array */ private readonly array $refs; public function __construct( - ScalarFunction ...$refs, + ScalarFunction|string ...$refs, ) { $this->refs = $refs; } public function eval(Row $row) : mixed { - $values = \array_map(function (ScalarFunction $ref) use ($row) : mixed { - return Caster::default()->to(type_string(true))->value($ref->eval($row)); + $values = \array_map(function (ScalarFunction|string $string) use ($row) : mixed { + return \is_string($string) ? $string : Caster::default()->to(type_string(true))->value($string->eval($row)); }, $this->refs); foreach ($values as $value) { diff --git a/src/core/etl/src/Flow/ETL/Function/Contains.php b/src/core/etl/src/Flow/ETL/Function/Contains.php index 0d674a342..c7d9f3ab6 100644 --- a/src/core/etl/src/Flow/ETL/Function/Contains.php +++ b/src/core/etl/src/Flow/ETL/Function/Contains.php @@ -8,16 +8,18 @@ final class Contains extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $haystack, private readonly ScalarFunction $needle) - { + public function __construct( + private readonly ScalarFunction|string $haystack, + private readonly ScalarFunction|string $needle + ) { } public function eval(Row $row) : bool { - $haystack = $this->haystack->eval($row); - $needle = $this->needle->eval($row); + $haystack = (new Parameter($this->haystack))->asString($row); + $needle = (new Parameter($this->needle))->asString($row); - if (!\is_string($needle) || !\is_string($haystack)) { + if ($haystack === null || $needle === null) { return false; } diff --git a/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php b/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php index 03f0c3055..d0b1b3aa4 100644 --- a/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php +++ b/src/core/etl/src/Flow/ETL/Function/DOMElementAttributeValue.php @@ -8,33 +8,26 @@ final class DOMElementAttributeValue extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref, private readonly ScalarFunction|string $attribute) - { + public function __construct( + private readonly ScalarFunction|\DOMElement $domElement, + private readonly ScalarFunction|string $attribute + ) { } public function eval(Row $row) : ?string { - $value = $this->ref->eval($row); - - if ($value instanceof \DOMAttr) { - return $value->nodeValue; - } + $domElement = (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class); + $attributeName = (new Parameter($this->attribute))->asString($row); - if (!$value instanceof \DOMElement) { + if ($domElement === null || $attributeName === null) { return null; } - if (!$value->hasAttributes()) { - return null; - } - - $attributeName = \is_string($this->attribute) ? $this->attribute : $this->attribute->eval($row); - - if (!\is_string($attributeName)) { + if (!$domElement->hasAttributes()) { return null; } - $attributes = $value->attributes; + $attributes = $domElement->attributes; if (!$namedItem = $attributes->getNamedItem($attributeName)) { return null; diff --git a/src/core/etl/src/Flow/ETL/Function/DOMElementAttributesCount.php b/src/core/etl/src/Flow/ETL/Function/DOMElementAttributesCount.php index 20196fee8..0ec1b06d7 100644 --- a/src/core/etl/src/Flow/ETL/Function/DOMElementAttributesCount.php +++ b/src/core/etl/src/Flow/ETL/Function/DOMElementAttributesCount.php @@ -8,26 +8,22 @@ final class DOMElementAttributesCount extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref) + public function __construct(private readonly ScalarFunction|\DOMElement $domElement) { } public function eval(Row $row) : ?int { - $value = $this->ref->eval($row); + $domElement = (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class); - if ($value instanceof \DOMAttr) { + if ($domElement === null) { return null; } - if (!$value instanceof \DOMElement) { - return null; - } - - if (!$value->hasAttributes()) { + if (!$domElement->hasAttributes()) { return 0; } - return $value->attributes->length; + return $domElement->attributes->length; } } diff --git a/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php b/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php index 8927e2d47..d214869db 100644 --- a/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php +++ b/src/core/etl/src/Flow/ETL/Function/DOMElementValue.php @@ -8,19 +8,18 @@ final class DOMElementValue extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref) + public function __construct(private readonly ScalarFunction|\DOMElement $domElement) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $domElement = (new Parameter($this->domElement))->asInstanceOf($row, \DOMElement::class); - if (!$value instanceof \DOMElement) { + if (!$domElement instanceof \DOMElement) { return null; } - return $value->nodeValue; + return $domElement->nodeValue; } } diff --git a/src/core/etl/src/Flow/ETL/Function/DateTimeFormat.php b/src/core/etl/src/Flow/ETL/Function/DateTimeFormat.php index f708be8b1..4f6c908da 100644 --- a/src/core/etl/src/Flow/ETL/Function/DateTimeFormat.php +++ b/src/core/etl/src/Flow/ETL/Function/DateTimeFormat.php @@ -9,19 +9,20 @@ final class DateTimeFormat extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly string $format + private readonly ScalarFunction|\DateTimeInterface $dateTime, + private readonly ScalarFunction|string $format ) { } public function eval(Row $row) : mixed { - $value = $this->ref->eval($row); + $value = (new Parameter($this->dateTime))->asInstanceOf($row, \DateTimeInterface::class); + $format = (new Parameter($this->format))->asString($row); - if (!$value instanceof \DateTimeInterface) { + if ($value === null || $format === null) { return null; } - return $value->format($this->format); + return $value->format($format); } } diff --git a/src/core/etl/src/Flow/ETL/Function/Divide.php b/src/core/etl/src/Flow/ETL/Function/Divide.php index cab6ab445..ea7a2d2ff 100644 --- a/src/core/etl/src/Flow/ETL/Function/Divide.php +++ b/src/core/etl/src/Flow/ETL/Function/Divide.php @@ -9,17 +9,17 @@ final class Divide extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float|string $left, + private readonly ScalarFunction|int|float|string $right ) { } public function eval(Row $row) : mixed { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($left === null || $right === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/EndsWith.php b/src/core/etl/src/Flow/ETL/Function/EndsWith.php index 505256597..6dbe7a0b9 100644 --- a/src/core/etl/src/Flow/ETL/Function/EndsWith.php +++ b/src/core/etl/src/Flow/ETL/Function/EndsWith.php @@ -9,17 +9,17 @@ final class EndsWith extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $haystack, - private readonly ScalarFunction $needle + private readonly ScalarFunction|string $haystack, + private readonly ScalarFunction|string $needle ) { } public function eval(Row $row) : bool { - $haystack = $this->haystack->eval($row); - $needle = $this->needle->eval($row); + $haystack = (new Parameter($this->haystack))->asString($row); + $needle = (new Parameter($this->needle))->asString($row); - if (!\is_string($needle) || !\is_string($haystack)) { + if ($haystack === null || $needle === null) { return false; } diff --git a/src/core/etl/src/Flow/ETL/Function/Equals.php b/src/core/etl/src/Flow/ETL/Function/Equals.php index ddbda6800..d8bd9a420 100644 --- a/src/core/etl/src/Flow/ETL/Function/Equals.php +++ b/src/core/etl/src/Flow/ETL/Function/Equals.php @@ -12,18 +12,18 @@ final class Equals extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '=='); + $this->assertComparable($left, $right, '=='); - return $base == $next; + return $left == $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/GreaterThan.php b/src/core/etl/src/Flow/ETL/Function/GreaterThan.php index be189694f..36a3a4b3c 100644 --- a/src/core/etl/src/Flow/ETL/Function/GreaterThan.php +++ b/src/core/etl/src/Flow/ETL/Function/GreaterThan.php @@ -12,22 +12,22 @@ final class GreaterThan extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '>'); + $this->assertComparable($left, $right, '>'); - if ($base === null || $next === null) { + if ($left === null || $right === null) { return false; } - return $base > $next; + return $left > $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/GreaterThanEqual.php b/src/core/etl/src/Flow/ETL/Function/GreaterThanEqual.php index 4caf84ca2..9431c8dea 100644 --- a/src/core/etl/src/Flow/ETL/Function/GreaterThanEqual.php +++ b/src/core/etl/src/Flow/ETL/Function/GreaterThanEqual.php @@ -12,22 +12,22 @@ final class GreaterThanEqual extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '>='); + $this->assertComparable($left, $right, '>='); - if ($base === null || $next === null) { + if ($left === null || $right === null) { return false; } - return $base >= $next; + return $left >= $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/Hash.php b/src/core/etl/src/Flow/ETL/Function/Hash.php index 530d0fb1f..9f0e424b1 100644 --- a/src/core/etl/src/Flow/ETL/Function/Hash.php +++ b/src/core/etl/src/Flow/ETL/Function/Hash.php @@ -10,15 +10,14 @@ final class Hash extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, + private readonly mixed $value, private readonly Algorithm $algorithm = new NativePHPHash(), ) { } public function eval(Row $row) : ?string { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->eval($row); return match ($value) { null => null, diff --git a/src/core/etl/src/Flow/ETL/Function/IsIn.php b/src/core/etl/src/Flow/ETL/Function/IsIn.php index a4c7888a4..4ffb4e259 100644 --- a/src/core/etl/src/Flow/ETL/Function/IsIn.php +++ b/src/core/etl/src/Flow/ETL/Function/IsIn.php @@ -9,17 +9,17 @@ final class IsIn extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $haystack, - private readonly ScalarFunction $needle + private readonly ScalarFunction|array $haystack, + private readonly mixed $needle ) { } public function eval(Row $row) : bool { - $haystack = $this->haystack->eval($row); - $needle = $this->needle->eval($row); + $haystack = (new Parameter($this->haystack))->asArray($row); + $needle = (new Parameter($this->needle))->eval($row); - if (!\is_array($haystack)) { + if ($haystack === null) { return false; } diff --git a/src/core/etl/src/Flow/ETL/Function/IsNotNull.php b/src/core/etl/src/Flow/ETL/Function/IsNotNull.php index 4d5232c54..5e7a72eb4 100644 --- a/src/core/etl/src/Flow/ETL/Function/IsNotNull.php +++ b/src/core/etl/src/Flow/ETL/Function/IsNotNull.php @@ -9,12 +9,12 @@ final class IsNotNull extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref + private readonly mixed $value ) { } public function eval(Row $row) : bool { - return $this->ref->eval($row) !== null; + return (new Parameter($this->value))->eval($row) !== null; } } diff --git a/src/core/etl/src/Flow/ETL/Function/IsNotNumeric.php b/src/core/etl/src/Flow/ETL/Function/IsNotNumeric.php index 937c04f5f..562c41f45 100644 --- a/src/core/etl/src/Flow/ETL/Function/IsNotNumeric.php +++ b/src/core/etl/src/Flow/ETL/Function/IsNotNumeric.php @@ -9,12 +9,12 @@ final class IsNotNumeric extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref + private readonly mixed $value ) { } public function eval(Row $row) : bool { - return !\is_numeric($this->ref->eval($row)); + return (new Parameter($this->value))->asNumber($row) === null; } } diff --git a/src/core/etl/src/Flow/ETL/Function/IsNull.php b/src/core/etl/src/Flow/ETL/Function/IsNull.php index a85d4c046..d970d34dc 100644 --- a/src/core/etl/src/Flow/ETL/Function/IsNull.php +++ b/src/core/etl/src/Flow/ETL/Function/IsNull.php @@ -9,12 +9,12 @@ final class IsNull extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref + private readonly mixed $value ) { } public function eval(Row $row) : bool { - return $this->ref->eval($row) === null; + return (new Parameter($this->value))->eval($row) === null; } } diff --git a/src/core/etl/src/Flow/ETL/Function/IsNumeric.php b/src/core/etl/src/Flow/ETL/Function/IsNumeric.php index 7a5fe90e6..0a07e69fd 100644 --- a/src/core/etl/src/Flow/ETL/Function/IsNumeric.php +++ b/src/core/etl/src/Flow/ETL/Function/IsNumeric.php @@ -9,12 +9,12 @@ final class IsNumeric extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref + private readonly mixed $value ) { } public function eval(Row $row) : bool { - return \is_numeric($this->ref->eval($row)); + return (new Parameter($this->value))->asNumber($row) !== null; } } diff --git a/src/core/etl/src/Flow/ETL/Function/IsType.php b/src/core/etl/src/Flow/ETL/Function/IsType.php index 5e6e9528a..60f6ab236 100644 --- a/src/core/etl/src/Flow/ETL/Function/IsType.php +++ b/src/core/etl/src/Flow/ETL/Function/IsType.php @@ -4,49 +4,35 @@ namespace Flow\ETL\Function; -use Flow\ETL\Exception\InvalidArgumentException; +use Flow\ETL\PHP\Type\{Type, TypeFactory}; use Flow\ETL\Row; -use Flow\ETL\Row\{Entry, Reference}; final class IsType extends ScalarFunctionChain { /** - * @var array> + * @var array */ - private array $typeClasses; + private array $types; /** - * @param class-string ...$typeClasses - * - * @throws InvalidArgumentException + * @param string|Type ...$types */ public function __construct( - private readonly ScalarFunction $ref, - string ...$typeClasses + private readonly mixed $value, + string|Type ...$types ) { - foreach ($typeClasses as $typeClass) { - if (!\class_exists($typeClass) || !\in_array(Entry::class, \class_implements($typeClass), true)) { - throw new InvalidArgumentException('"' . $typeClass . '" is not valid Entry Type class'); - } - } - $this->typeClasses = $typeClasses; + $this->types = $types; } public function eval(Row $row) : bool { - if (!$this->ref instanceof Reference) { - return false; - } - - if (!$row->has($this->ref)) { - return false; - } + $value = (new Parameter($this->value))->eval($row); - $entry = $row->get($this->ref); + foreach ($this->types as $type) { + $type = \is_string($type) ? TypeFactory::fromString($type) : $type; - foreach ($this->typeClasses as $typeClass) { - if (\is_a($entry, $typeClass, true)) { + if ($type->isValid($value)) { return true; } } diff --git a/src/core/etl/src/Flow/ETL/Function/JsonDecode.php b/src/core/etl/src/Flow/ETL/Function/JsonDecode.php index c79cd8303..d12118f56 100644 --- a/src/core/etl/src/Flow/ETL/Function/JsonDecode.php +++ b/src/core/etl/src/Flow/ETL/Function/JsonDecode.php @@ -8,21 +8,23 @@ final class JsonDecode extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref, private readonly int $flags = JSON_THROW_ON_ERROR) - { + public function __construct( + private readonly ScalarFunction $value, + private readonly ScalarFunction|int $flags = JSON_THROW_ON_ERROR + ) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->asString($row); + $flags = (int) (new Parameter($this->flags))->asInt($row); - if (!\is_string($value)) { + if ($value === null) { return null; } try { - return \json_decode($value, true, 512, $this->flags); + return \json_decode($value, true, 512, $flags); } catch (\JsonException $e) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/JsonEncode.php b/src/core/etl/src/Flow/ETL/Function/JsonEncode.php index 78367b5ed..2f00ae87d 100644 --- a/src/core/etl/src/Flow/ETL/Function/JsonEncode.php +++ b/src/core/etl/src/Flow/ETL/Function/JsonEncode.php @@ -8,17 +8,19 @@ final class JsonEncode extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref, private readonly int $flags = JSON_THROW_ON_ERROR) - { + public function __construct( + private readonly ScalarFunction $value, + private readonly ScalarFunction|int $flags = JSON_THROW_ON_ERROR + ) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->eval($row); + $flags = (int) (new Parameter($this->flags))->asInt($row); try { - return \json_encode($value, $this->flags); + return \json_encode($value, $flags); } catch (\JsonException $e) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/LessThan.php b/src/core/etl/src/Flow/ETL/Function/LessThan.php index 0f2d3c5ed..d5ce16870 100644 --- a/src/core/etl/src/Flow/ETL/Function/LessThan.php +++ b/src/core/etl/src/Flow/ETL/Function/LessThan.php @@ -12,22 +12,22 @@ final class LessThan extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '<'); + $this->assertComparable($left, $right, '<'); - if ($base === null || $next === null) { + if ($left === null || $right === null) { return false; } - return $base < $next; + return $left < $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/LessThanEqual.php b/src/core/etl/src/Flow/ETL/Function/LessThanEqual.php index 11dd116f8..a692a2d6f 100644 --- a/src/core/etl/src/Flow/ETL/Function/LessThanEqual.php +++ b/src/core/etl/src/Flow/ETL/Function/LessThanEqual.php @@ -12,22 +12,22 @@ final class LessThanEqual extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '<='); + $this->assertComparable($left, $right, '<='); - if ($base === null || $next === null) { + if ($left === null || $right === null) { return false; } - return $base <= $next; + return $left <= $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/Minus.php b/src/core/etl/src/Flow/ETL/Function/Minus.php index cb20df209..5bf9330f1 100644 --- a/src/core/etl/src/Flow/ETL/Function/Minus.php +++ b/src/core/etl/src/Flow/ETL/Function/Minus.php @@ -9,17 +9,17 @@ final class Minus extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float $left, + private readonly ScalarFunction|int|float $right ) { } public function eval(Row $row) : mixed { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($left === null || $right === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/Mod.php b/src/core/etl/src/Flow/ETL/Function/Mod.php index 8e087c02e..2c8179973 100644 --- a/src/core/etl/src/Flow/ETL/Function/Mod.php +++ b/src/core/etl/src/Flow/ETL/Function/Mod.php @@ -9,21 +9,21 @@ final class Mod extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float $left, + private readonly ScalarFunction|int|float $right ) { } public function eval(Row $row) : mixed { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if ($right === 0) { + if ($left === null || $right === null) { return null; } - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($right === 0) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/Multiply.php b/src/core/etl/src/Flow/ETL/Function/Multiply.php index 0ca23773f..a8e3be684 100644 --- a/src/core/etl/src/Flow/ETL/Function/Multiply.php +++ b/src/core/etl/src/Flow/ETL/Function/Multiply.php @@ -9,17 +9,17 @@ final class Multiply extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float $left, + private readonly ScalarFunction|int|float $right ) { } public function eval(Row $row) : mixed { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($left === null || $right === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/Not.php b/src/core/etl/src/Flow/ETL/Function/Not.php index 943624bcd..0e3ac276c 100644 --- a/src/core/etl/src/Flow/ETL/Function/Not.php +++ b/src/core/etl/src/Flow/ETL/Function/Not.php @@ -8,12 +8,12 @@ final class Not extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $function) + public function __construct(private readonly ScalarFunction $value) { } public function eval(Row $row) : mixed { - return !$this->function->eval($row); + return !$this->value->eval($row); } } diff --git a/src/core/etl/src/Flow/ETL/Function/NotEquals.php b/src/core/etl/src/Flow/ETL/Function/NotEquals.php index 1135dfcc3..b6e02b666 100644 --- a/src/core/etl/src/Flow/ETL/Function/NotEquals.php +++ b/src/core/etl/src/Flow/ETL/Function/NotEquals.php @@ -12,18 +12,18 @@ final class NotEquals extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '!='); + $this->assertComparable($left, $right, '!='); - return $base != $next; + return $left != $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/NotSame.php b/src/core/etl/src/Flow/ETL/Function/NotSame.php index 70116cbbe..cb9051ac0 100644 --- a/src/core/etl/src/Flow/ETL/Function/NotSame.php +++ b/src/core/etl/src/Flow/ETL/Function/NotSame.php @@ -12,18 +12,18 @@ final class NotSame extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $left = (new Parameter($this->left))->eval($row); + $right = (new Parameter($this->right))->eval($row); - $this->assertComparable($base, $next, '!=='); + $this->assertComparable($left, $right, '!=='); - return $base !== $next; + return $left !== $right; } } diff --git a/src/core/etl/src/Flow/ETL/Function/Now.php b/src/core/etl/src/Flow/ETL/Function/Now.php index 52f502b8c..d16797e2e 100644 --- a/src/core/etl/src/Flow/ETL/Function/Now.php +++ b/src/core/etl/src/Flow/ETL/Function/Now.php @@ -8,12 +8,18 @@ final class Now extends ScalarFunctionChain { - public function __construct(private readonly \DateTimeZone $timeZone = new \DateTimeZone('UTC')) + public function __construct(private readonly ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC')) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : ?\DateTimeImmutable { - return new \DateTimeImmutable('now', $this->timeZone); + $tz = (new Parameter($this->timeZone))->asInstanceOf($row, \DateTimeZone::class); + + if ($tz === null) { + return null; + } + + return new \DateTimeImmutable('now', $tz); } } diff --git a/src/core/etl/src/Flow/ETL/Function/NumberFormat.php b/src/core/etl/src/Flow/ETL/Function/NumberFormat.php index b91503d90..e5573d9af 100644 --- a/src/core/etl/src/Flow/ETL/Function/NumberFormat.php +++ b/src/core/etl/src/Flow/ETL/Function/NumberFormat.php @@ -9,25 +9,21 @@ final class NumberFormat extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly ScalarFunction $decimals, - private readonly ScalarFunction $decimalSeparator, - private readonly ScalarFunction $thousandsSeparator + private readonly ScalarFunction|int|float $value, + private readonly ScalarFunction|int $decimals, + private readonly ScalarFunction|string $decimalSeparator = '.', + private readonly ScalarFunction|string $thousandsSeparator = ',' ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : ?string { - $value = $this->ref->eval($row); - $decimals = $this->decimals->eval($row); - $decimalSeparator = $this->decimalSeparator->eval($row); - $thousandsSeparator = $this->thousandsSeparator->eval($row); + $value = (new Parameter($this->value))->asNumber($row); + $decimals = (new Parameter($this->decimals))->asInt($row); + $decimalSeparator = (new Parameter($this->decimalSeparator))->asString($row); + $thousandsSeparator = (new Parameter($this->thousandsSeparator))->asString($row); - if (!\is_numeric($value)) { - return null; - } - - if (!\is_int($decimals)) { + if ($value === null || $decimals === null || $decimalSeparator === null || $thousandsSeparator === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/OnEach.php b/src/core/etl/src/Flow/ETL/Function/OnEach.php index 6105680eb..0623735a5 100644 --- a/src/core/etl/src/Flow/ETL/Function/OnEach.php +++ b/src/core/etl/src/Flow/ETL/Function/OnEach.php @@ -11,7 +11,7 @@ final class OnEach extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, + private readonly ScalarFunction|array $array, private readonly ScalarFunction $function, private readonly ScalarFunction|bool $preserveKeys = true ) { @@ -19,14 +19,13 @@ public function __construct( public function eval(Row $row) : mixed { - $value = $this->ref->eval($row); + $value = (new Parameter($this->array))->asArray($row); + $preserveKeys = (new Parameter($this->preserveKeys))->asBoolean($row); - if (!\is_array($value)) { + if ($value === null) { return null; } - $preserveKeys = \is_bool($this->preserveKeys) ? $this->preserveKeys : (bool) $this->preserveKeys->eval($row); - $output = []; foreach ($value as $key => $item) { diff --git a/src/core/etl/src/Flow/ETL/Function/Parameter.php b/src/core/etl/src/Flow/ETL/Function/Parameter.php new file mode 100644 index 000000000..e7e61cc9e --- /dev/null +++ b/src/core/etl/src/Flow/ETL/Function/Parameter.php @@ -0,0 +1,133 @@ +function = $function instanceof ScalarFunction ? $function : lit($function); + } + + public static function oneOf(mixed ...$values) : mixed + { + foreach ($values as $value) { + if ($value !== null) { + return $value; + } + } + + return null; + } + + public function asArray(Row $row) : ?array + { + $result = $this->function->eval($row); + + return \is_array($result) ? $result : null; + } + + public function asBoolean(Row $row) : bool + { + return (bool) $this->function->eval($row); + } + + public function asDateTime(Row $row) : ?\DateTimeInterface + { + $result = $this->function->eval($row); + + return $result instanceof \DateTimeInterface ? $result : null; + } + + /** + * @psalm-suppress InvalidReturnType + * @psalm-suppress InvalidReturnStatement + * + * @template T of \UnitEnum + * + * @param Row $row + * @param class-string $enumClass + * + * @return null|T + */ + public function asEnum(Row $row, string $enumClass) : ?\UnitEnum + { + $result = $this->function->eval($row); + + return \is_a($result, $enumClass) ? $result : null; + } + + public function asFloat(Row $row) : ?float + { + $result = $this->function->eval($row); + + return \is_float($result) ? $result : null; + } + + /** + * @psalm-suppress InvalidReturnType + * @psalm-suppress InvalidReturnStatement + * + * @template T of object + * + * @param Row $row + * @param class-string $class + * + * @return null|T + */ + public function asInstanceOf(Row $row, string $class) : ?object + { + $result = $this->function->eval($row); + + return \is_a($result, $class) ? $result : null; + } + + public function asInt(Row $row) : ?int + { + $result = $this->function->eval($row); + + return \is_int($result) ? $result : null; + } + + /** + * @psalm-suppress InvalidReturnType + * @psalm-suppress InvalidReturnStatement + */ + public function asNumber(Row $row) : int|float|null + { + $result = $this->function->eval($row); + + if (\is_string($result)) { + return null; + } + + return \is_numeric($result) ? $result : null; + } + + public function asObject(Row $row) : ?object + { + $result = $this->function->eval($row); + + return \is_object($result) ? $result : null; + } + + public function asString(Row $row) : ?string + { + $result = $this->function->eval($row); + + return \is_string($result) ? $result : null; + } + + public function eval(Row $row) : mixed + { + return $this->function->eval($row); + } +} diff --git a/src/core/etl/src/Flow/ETL/Function/Plus.php b/src/core/etl/src/Flow/ETL/Function/Plus.php index 340d01071..66eb935b9 100644 --- a/src/core/etl/src/Flow/ETL/Function/Plus.php +++ b/src/core/etl/src/Flow/ETL/Function/Plus.php @@ -9,17 +9,17 @@ final class Plus extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float $left, + private readonly ScalarFunction|int|float $right ) { } public function eval(Row $row) : mixed { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($left === null || $right === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/Power.php b/src/core/etl/src/Flow/ETL/Function/Power.php index a1dbb8128..928fafede 100644 --- a/src/core/etl/src/Flow/ETL/Function/Power.php +++ b/src/core/etl/src/Flow/ETL/Function/Power.php @@ -9,21 +9,21 @@ final class Power extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float $left, + private readonly ScalarFunction|int|float $right ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : float|int|null { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if ($right === 0) { + if ($left === null || $right === null) { return null; } - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($right === 0) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/RandomString.php b/src/core/etl/src/Flow/ETL/Function/RandomString.php index b427e14da..e8169ccb2 100644 --- a/src/core/etl/src/Flow/ETL/Function/RandomString.php +++ b/src/core/etl/src/Flow/ETL/Function/RandomString.php @@ -8,18 +8,20 @@ class RandomString implements ScalarFunction { - private RandomValueGenerator|NativePHPRandomValueGenerator $generator; - - private int|ScalarFunction $length; - - public function __construct(ScalarFunction|int $length, RandomValueGenerator $generator = new NativePHPRandomValueGenerator()) - { - $this->length = $length; - $this->generator = $generator; + public function __construct( + private readonly ScalarFunction|int $length, + private readonly RandomValueGenerator $generator = new NativePHPRandomValueGenerator() + ) { } - public function eval(Row $row) : string + public function eval(Row $row) : ?string { - return $this->generator->string(is_int($this->length) ? $this->length : $this->length->eval($row)); + $length = (new Parameter($this->length))->asInt($row); + + if ($length === null) { + return null; + } + + return $this->generator->string($length); } } diff --git a/src/core/etl/src/Flow/ETL/Function/Regex.php b/src/core/etl/src/Flow/ETL/Function/Regex.php index 457901c2c..8166e1367 100644 --- a/src/core/etl/src/Flow/ETL/Function/Regex.php +++ b/src/core/etl/src/Flow/ETL/Function/Regex.php @@ -9,27 +9,27 @@ final class Regex extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $pattern, - private readonly ScalarFunction $subject, - private readonly ?ScalarFunction $flags = null, - private readonly ?ScalarFunction $offset = null, + private readonly ScalarFunction|string $pattern, + private readonly ScalarFunction|string|array $subject, + private readonly ScalarFunction|int $flags = 0, + private readonly ScalarFunction|int $offset = 0, ) { } public function eval(Row $row) : ?array { - /** @var array|non-empty-string $pattern */ - $pattern = $this->pattern->eval($row); - $subject = $this->subject->eval($row); - $flags = $this->flags ? $this->flags->eval($row) : 0; - $offset = $this->offset ? $this->offset->eval($row) : 0; + $pattern = (new Parameter($this->pattern))->asString($row); + $subject = (new Parameter($this->subject))->asString($row); + $flags = (new Parameter($this->flags))->asInt($row); + $offset = (new Parameter($this->offset))->asInt($row); - if (!\is_string($pattern) || !\is_string($subject) || !\is_int($flags) || !\is_int($offset)) { + if ($pattern === null || $subject === null || $flags === null || $offset === null) { return null; } // preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or false on failure. - if (\preg_match($pattern, $subject, $matches) === 1) { + /* @phpstan-ignore-next-line */ + if (\preg_match($pattern, $subject, $matches, $flags, $offset) === 1) { return $matches; } diff --git a/src/core/etl/src/Flow/ETL/Function/RegexAll.php b/src/core/etl/src/Flow/ETL/Function/RegexAll.php index 100224f18..d56f59e18 100644 --- a/src/core/etl/src/Flow/ETL/Function/RegexAll.php +++ b/src/core/etl/src/Flow/ETL/Function/RegexAll.php @@ -9,22 +9,21 @@ final class RegexAll extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $pattern, - private readonly ScalarFunction $subject, - private readonly ?ScalarFunction $flags = null, - private readonly ?ScalarFunction $offset = null, + private readonly ScalarFunction|string $pattern, + private readonly ScalarFunction|string|array $subject, + private readonly ScalarFunction|int $flags = 0, + private readonly ScalarFunction|int $offset = 0, ) { } public function eval(Row $row) : ?array { - /** @var array|non-empty-string $pattern */ - $pattern = $this->pattern->eval($row); - $subject = $this->subject->eval($row); - $flags = $this->flags ? $this->flags->eval($row) : 0; - $offset = $this->offset ? $this->offset->eval($row) : 0; + $pattern = (new Parameter($this->pattern))->asString($row); + $subject = (new Parameter($this->subject))->asString($row); + $flags = (new Parameter($this->flags))->asInt($row); + $offset = (new Parameter($this->offset))->asInt($row); - if (!\is_string($pattern) || !\is_string($subject) || !\is_int($flags) || !\is_int($offset)) { + if ($pattern === null || $subject === null || $flags === null || $offset === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/RegexMatch.php b/src/core/etl/src/Flow/ETL/Function/RegexMatch.php index 60fd0a1bd..c36e88e9f 100644 --- a/src/core/etl/src/Flow/ETL/Function/RegexMatch.php +++ b/src/core/etl/src/Flow/ETL/Function/RegexMatch.php @@ -9,22 +9,21 @@ final class RegexMatch extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $pattern, - private readonly ScalarFunction $subject, - private readonly ?ScalarFunction $flags = null, - private readonly ?ScalarFunction $offset = null, + private readonly ScalarFunction|string $pattern, + private readonly ScalarFunction|string|array $subject, + private readonly ScalarFunction|int $flags = 0, + private readonly ScalarFunction|int $offset = 0, ) { } public function eval(Row $row) : ?bool { - /** @var non-empty-string $pattern */ - $pattern = $this->pattern->eval($row); - $subject = $this->subject->eval($row); - $flags = $this->flags ? $this->flags->eval($row) : 0; - $offset = $this->offset ? $this->offset->eval($row) : 0; + $pattern = (new Parameter($this->pattern))->asString($row); + $subject = (new Parameter($this->subject))->asString($row); + $flags = (new Parameter($this->flags))->asInt($row); + $offset = (new Parameter($this->offset))->asInt($row); - if (!\is_string($pattern) || !\is_string($subject) || !\is_int($flags) || !\is_int($offset)) { + if ($pattern === null || $subject === null || $flags === null || $offset === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/RegexMatchAll.php b/src/core/etl/src/Flow/ETL/Function/RegexMatchAll.php index ffe579d20..16830cf85 100644 --- a/src/core/etl/src/Flow/ETL/Function/RegexMatchAll.php +++ b/src/core/etl/src/Flow/ETL/Function/RegexMatchAll.php @@ -9,22 +9,21 @@ final class RegexMatchAll extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $pattern, - private readonly ScalarFunction $subject, - private readonly ?ScalarFunction $flags = null, - private readonly ?ScalarFunction $offset = null, + private readonly ScalarFunction|string $pattern, + private readonly ScalarFunction|string|array $subject, + private readonly ScalarFunction|int $flags = 0, + private readonly ScalarFunction|int $offset = 0, ) { } public function eval(Row $row) : ?bool { - /** @var non-empty-string $pattern */ - $pattern = $this->pattern->eval($row); - $subject = $this->subject->eval($row); - $flags = $this->flags ? $this->flags->eval($row) : 0; - $offset = $this->offset ? $this->offset->eval($row) : 0; + $pattern = (new Parameter($this->pattern))->asString($row); + $subject = (new Parameter($this->subject))->asString($row); + $flags = (new Parameter($this->flags))->asInt($row); + $offset = (new Parameter($this->offset))->asInt($row); - if (!\is_string($pattern) || !\is_string($subject) || !\is_int($flags) || !\is_int($offset)) { + if ($pattern === null || $subject === null || $flags === null || $offset === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/RegexReplace.php b/src/core/etl/src/Flow/ETL/Function/RegexReplace.php index 5b3711451..e8c95c039 100644 --- a/src/core/etl/src/Flow/ETL/Function/RegexReplace.php +++ b/src/core/etl/src/Flow/ETL/Function/RegexReplace.php @@ -9,25 +9,21 @@ final class RegexReplace extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $pattern, - private readonly ScalarFunction $replacement, - private readonly ScalarFunction $subject, - private readonly ?ScalarFunction $limit = null, + private readonly ScalarFunction|string $pattern, + private readonly ScalarFunction|string $replacement, + private readonly ScalarFunction|string $subject, + private readonly ScalarFunction|int|null $limit = null, ) { } public function eval(Row $row) : ?string { - /** @var array|non-empty-string $pattern */ - $pattern = $this->pattern->eval($row); - /** @var mixed $replacement */ - $replacement = $this->replacement->eval($row); - /** @var mixed $subject */ - $subject = $this->subject->eval($row); + $pattern = (new Parameter($this->pattern))->asString($row); + $replacement = (new Parameter($this->replacement))->asString($row); + $subject = (new Parameter($this->subject))->asString($row); + $limit = $this->limit ? (new Parameter($this->limit))->asInt($row) : -1; - $limit = $this->limit ? $this->limit->eval($row) : -1; - - if (!\is_string($pattern) || !\is_string($replacement) || !\is_string($subject) || !\is_int($limit)) { + if ($pattern === null || $replacement === null || $subject === null || $limit === null) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/Round.php b/src/core/etl/src/Flow/ETL/Function/Round.php index eaf67d768..ef49e271e 100644 --- a/src/core/etl/src/Flow/ETL/Function/Round.php +++ b/src/core/etl/src/Flow/ETL/Function/Round.php @@ -8,28 +8,27 @@ final class Round extends ScalarFunctionChain { - /** - * @param ScalarFunction $entry - * @param ScalarFunction $precision - * @param int<0, max> $mode - */ public function __construct( - private readonly ScalarFunction $entry, - private readonly ScalarFunction $precision, - private readonly int $mode = PHP_ROUND_HALF_UP, + private readonly ScalarFunction|int|float $value, + private readonly ScalarFunction|int $precision = 0, + private readonly ScalarFunction|int $mode = PHP_ROUND_HALF_UP, ) { } public function eval(Row $row) : ?float { - /** @var mixed $value */ - $value = $this->entry->eval($row); + $value = (new Parameter($this->value))->asNumber($row); + $precision = (new Parameter($this->precision))->asInt($row); + $mode = (new Parameter($this->mode))->asInt($row); - if (!\is_float($value) && !\is_int($value)) { + if ($value === null || $precision === null || $mode === null) { return null; } - /** @phpstan-ignore-next-line */ - return \round($value, (int) $this->precision->eval($row), $this->mode); + if ($mode < 1 || $mode > 4) { + $mode = 1; + } + + return \round($value, $precision, $mode); } } diff --git a/src/core/etl/src/Flow/ETL/Function/Same.php b/src/core/etl/src/Flow/ETL/Function/Same.php index e8a480ac4..012536f42 100644 --- a/src/core/etl/src/Flow/ETL/Function/Same.php +++ b/src/core/etl/src/Flow/ETL/Function/Same.php @@ -12,15 +12,15 @@ final class Same extends ScalarFunctionChain use Comparable; public function __construct( - private readonly ScalarFunction $base, - private readonly ScalarFunction $next + private readonly mixed $left, + private readonly mixed $right ) { } public function eval(Row $row) : bool { - $base = $this->base->eval($row); - $next = $this->next->eval($row); + $base = (new Parameter($this->left))->eval($row); + $next = (new Parameter($this->right))->eval($row); $this->assertComparable($base, $next, '==='); diff --git a/src/core/etl/src/Flow/ETL/Function/Sanitize.php b/src/core/etl/src/Flow/ETL/Function/Sanitize.php index 97b4e92fd..a04fa6080 100644 --- a/src/core/etl/src/Flow/ETL/Function/Sanitize.php +++ b/src/core/etl/src/Flow/ETL/Function/Sanitize.php @@ -4,34 +4,30 @@ namespace Flow\ETL\Function; -use function Flow\ETL\DSL\{type_int, type_string}; -use Flow\ETL\PHP\Type\Caster; use Flow\ETL\Row; final class Sanitize extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly ScalarFunction $placeholder, - private readonly ScalarFunction $skipCharacters + private readonly ScalarFunction|string $value, + private readonly ScalarFunction|string $placeholder, + private readonly ScalarFunction|int|null $skipCharacters = null ) { } public function eval(Row $row) : ?string { - /** @var mixed $val */ - $val = $this->ref->eval($row); + $val = (new Parameter($this->value))->asString($row); + $placeholder = (new Parameter($this->placeholder))->asString($row); + $skipCharacters = (new Parameter($this->skipCharacters))->asInt($row); - if (!\is_string($val)) { + if ($val === null || $placeholder === null) { return null; } - $placeholder = Caster::default()->to(type_string(true))->value($this->placeholder->eval($row)); - $skipCharacters = Caster::default()->to(type_int(true))->value($this->skipCharacters->eval($row)); - $size = \mb_strlen($val); - if (0 !== $skipCharacters && $size > $skipCharacters) { + if ($skipCharacters !== null && $size > $skipCharacters) { return \mb_substr($val, 0, $skipCharacters) . \str_repeat($placeholder, $size - $skipCharacters); } diff --git a/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php b/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php index 93437c84f..e78e31a25 100644 --- a/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php +++ b/src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php @@ -4,7 +4,7 @@ namespace Flow\ETL\Function; -use function Flow\ETL\DSL\{lit, ref, type_string}; +use function Flow\ETL\DSL\lit; use Flow\ETL\Exception\InvalidArgumentException; use Flow\ETL\Function; use Flow\ETL\Function\ArrayExpand\ArrayExpand; @@ -16,12 +16,12 @@ abstract class ScalarFunctionChain implements ScalarFunction { - public function arrayGet(string $path) : self + public function arrayGet(ScalarFunction|string $path) : self { return new ArrayGet($this, $path); } - public function arrayGetCollection(string ...$keys) : self + public function arrayGetCollection(ScalarFunction|array $keys) : self { return new ArrayGetCollection($this, $keys); } @@ -31,7 +31,7 @@ public function arrayGetCollectionFirst(string ...$keys) : self return ArrayGetCollection::fromFirst($this, $keys); } - public function arrayMerge(ScalarFunction $ref) : self + public function arrayMerge(ScalarFunction|array $ref) : self { return new ArrayMerge($this, $ref); } @@ -41,17 +41,27 @@ public function arrayMergeCollection() : self return new ArrayMergeCollection($this); } - public function arrayReverse(bool $preserveKeys = false) : self + public function arrayPathExists(ScalarFunction|string $path) : self + { + return new ArrayPathExists($this, $path); + } + + public function arrayReverse(ScalarFunction|bool $preserveKeys = false) : self { return new ArrayReverse($this, $preserveKeys); } - public function arraySort(?string $algorithm = null, ?int $flags = null, bool $recursive = true) : self + public function arraySort(ScalarFunction|Sort|null $sortFunction = null, ScalarFunction|int|null $flags = null, ScalarFunction|bool $recursive = true) : self { - return new ArraySort($this, $algorithm ? Sort::fromString($algorithm) : Sort::sort, $flags, $recursive); + return new ArraySort($this, $sortFunction ?? Sort::sort, $flags, $recursive); } - public function between(ScalarFunction $lowerBoundRef, ScalarFunction $upperBoundRef, Boundary $boundary = Boundary::LEFT_INCLUSIVE) : self + /** + * @param mixed|ScalarFunction $lowerBoundRef + * @param mixed|ScalarFunction $upperBoundRef + * @param Boundary|ScalarFunction $boundary + */ + public function between(mixed $lowerBoundRef, mixed $upperBoundRef, ScalarFunction|Boundary $boundary = Boundary::LEFT_INCLUSIVE) : self { return new Between($this, $lowerBoundRef, $upperBoundRef, $boundary); } @@ -61,17 +71,17 @@ public function capitalize() : self return new Capitalize($this); } - public function cast(string|Type $type) : self + public function cast(ScalarFunction|string|Type $type) : self { return new Cast($this, $type); } - public function concat(ScalarFunction ...$params) : self + public function concat(ScalarFunction|string ...$params) : self { return new Concat($this, ...$params); } - public function contains(ScalarFunction $needle) : self + public function contains(ScalarFunction|string $needle) : self { return new Contains($this, $needle); } @@ -86,7 +96,7 @@ public function dateTimeFormat(string $format = 'Y-m-d H:i:s') : self return new DateTimeFormat($this, $format); } - public function divide(ScalarFunction $ref) : self + public function divide(ScalarFunction|int|float|string $ref) : self { return new Divide($this, $ref); } @@ -114,12 +124,12 @@ public function domElementValue() : self return new DOMElementValue($this); } - public function endsWith(ScalarFunction $needle) : self + public function endsWith(ScalarFunction|string $needle) : self { return new EndsWith($this, $needle); } - public function equals(ScalarFunction $ref) : self + public function equals(mixed $ref) : self { return new Equals($this, $ref); } @@ -154,12 +164,12 @@ public function expand(string $expandEntryName = 'element', ArrayExpand $expand return new Function\ArrayExpand($this, $expand); } - public function greaterThan(ScalarFunction $ref) : self + public function greaterThan(mixed $ref) : self { return new GreaterThan($this, $ref); } - public function greaterThanEqual(ScalarFunction $ref) : self + public function greaterThanEqual(mixed $ref) : self { return new GreaterThanEqual($this, $ref); } @@ -179,7 +189,7 @@ public function isFalse() : self return new Same($this, lit(false)); } - public function isIn(ScalarFunction $haystack) : self + public function isIn(ScalarFunction|array $haystack) : self { return new IsIn($haystack, $this); } @@ -214,29 +224,26 @@ public function isTrue() : self return new Same($this, lit(true)); } - /** - * @param class-string ...$entryClass - */ - public function isType(string ...$entryClass) : self + public function isType(string|Type ...$types) : self { - if ([] === $entryClass) { - throw new InvalidArgumentException('isType expression requires at least one entryClass'); + if ([] === $types) { + throw new InvalidArgumentException('isType expression requires at least one type'); } - return new IsType($this, ...$entryClass); + return new IsType($this, ...$types); } - public function jsonDecode(int $flags = JSON_THROW_ON_ERROR) : self + public function jsonDecode(ScalarFunction|int $flags = JSON_THROW_ON_ERROR) : self { return new JsonDecode($this, $flags); } - public function jsonEncode(int $flags = JSON_THROW_ON_ERROR) : self + public function jsonEncode(ScalarFunction|int $flags = JSON_THROW_ON_ERROR) : self { return new JsonEncode($this, $flags); } - public function lessThan(ScalarFunction $ref) : self + public function lessThan(mixed $ref) : self { return new LessThan($this, $ref); } @@ -256,50 +263,42 @@ public function lower() : self return new ToLower($this); } - public function method(ScalarFunction $method, ScalarFunction ...$params) : self + /** + * @param ScalarFunction|string $method + * @param array $params + */ + public function method(ScalarFunction|string $method, array $params) : self { - return new CallMethod($this, $method, ...$params); + return new CallMethod($this, $method, $params); } - public function minus(ScalarFunction $ref) : self + public function minus(ScalarFunction|int|float $ref) : self { return new Minus($this, $ref); } - public function mod(ScalarFunction $ref) : self + public function mod(ScalarFunction|int|float $value) : self { - return new Mod($this, $ref); + return new Mod($this, $value); } - public function multiply(ScalarFunction $ref) : self + public function multiply(ScalarFunction|int|float $value) : self { - return new Multiply($this, $ref); + return new Multiply($this, $value); } - public function notEquals(ScalarFunction $ref) : self + public function notEquals(mixed $value) : self { - return new NotEquals($this, $ref); + return new NotEquals($this, $value); } - public function notSame(ScalarFunction $ref) : self + public function notSame(mixed $value) : self { - return new NotSame($this, $ref); + return new NotSame($this, $value); } - public function numberFormat(?ScalarFunction $decimals = null, ?ScalarFunction $decimalSeparator = null, ?ScalarFunction $thousandsSeparator = null) : self + public function numberFormat(ScalarFunction|int $decimals = 2, ScalarFunction|string $decimalSeparator = '.', ScalarFunction|string $thousandsSeparator = ',') : self { - if ($decimals === null) { - $decimals = lit(0); - } - - if ($decimalSeparator === null) { - $decimalSeparator = lit('.'); - } - - if ($thousandsSeparator === null) { - $thousandsSeparator = lit(','); - } - return new NumberFormat($this, $decimals, $decimalSeparator, $thousandsSeparator); } @@ -309,12 +308,12 @@ public function numberFormat(?ScalarFunction $decimals = null, ?ScalarFunction $ * * Example: $df->withEntry('array', ref('array')->onEach(ref('element')->cast(type_string()))) */ - public function onEach(self $cast, ScalarFunction|bool $preserveKeys = true) : OnEach + public function onEach(ScalarFunction $function, ScalarFunction|bool $preserveKeys = true) : OnEach { - return new OnEach($this, $cast, $preserveKeys); + return new OnEach($this, $function, $preserveKeys); } - public function plus(ScalarFunction $ref) : self + public function plus(ScalarFunction|int|float $ref) : self { return new Plus($this, $ref); } @@ -324,48 +323,44 @@ public function power(ScalarFunction|int|float $value) : self return new Power($this, $value instanceof ScalarFunction ? $value : lit($value)); } - public function regex(ScalarFunction $pattern, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : self + public function regex(ScalarFunction|string $pattern, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : self { return new Regex($pattern, $this, $flags, $offset); } - public function regexAll(ScalarFunction $pattern, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : RegexAll + public function regexAll(ScalarFunction|string $pattern, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : RegexAll { return new RegexAll($pattern, $this, $flags, $offset); } - public function regexMatch(ScalarFunction $pattern, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : self + public function regexMatch(ScalarFunction|string $pattern, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : self { return new RegexMatch($pattern, $this, $flags, $offset); } - public function regexMatchAll(ScalarFunction $pattern, ?ScalarFunction $flags = null, ?ScalarFunction $offset = null) : self + public function regexMatchAll(ScalarFunction|string $pattern, ScalarFunction|int $flags = 0, ScalarFunction|int $offset = 0) : self { return new RegexMatchAll($pattern, $this, $flags, $offset); } - public function regexReplace(ScalarFunction $pattern, ScalarFunction $replacement, ?ScalarFunction $limit = null) : self + public function regexReplace(ScalarFunction|string $pattern, ScalarFunction|string $replacement, ScalarFunction|int|null $limit = null) : self { return new RegexReplace($pattern, $replacement, $this, $limit); } - /** - * @param ScalarFunction $precision - * @param int<0, max> $mode - */ - public function round(ScalarFunction $precision, int $mode = PHP_ROUND_HALF_UP) : self + public function round(ScalarFunction|int $precision = 2, ScalarFunction|int $mode = PHP_ROUND_HALF_UP) : self { return new Round($this, $precision, $mode); } - public function same(ScalarFunction $ref) : self + public function same(mixed $value) : self { - return new Same($this, $ref); + return new Same($this, $value); } - public function sanitize(?ScalarFunction $placeholder = null, ?ScalarFunction $skipCharacters = null) : self + public function sanitize(ScalarFunction|string $placeholder = '*', ScalarFunction|int|null $skipCharacters = null) : self { - return new Sanitize($this, $placeholder ?: new Literal('*'), $skipCharacters ?: new Literal(0)); + return new Sanitize($this, $placeholder, $skipCharacters); } public function size() : self @@ -378,12 +373,12 @@ public function split(ScalarFunction|string $separator, ScalarFunction|int $limi return new Split($this, $separator, $limit); } - public function sprintf(ScalarFunction ...$params) : self + public function sprintf(ScalarFunction|float|int|string|null ...$params) : self { return new Sprintf($this, ...$params); } - public function startsWith(ScalarFunction $needle) : self + public function startsWith(ScalarFunction|string $needle) : self { return new StartsWith($this, $needle); } @@ -409,28 +404,27 @@ public function strPadRight(int $length, string $pad_string = ' ') : self } /** - * @param string|string[] $search - * @param string|string[] $replace + * @param ScalarFunction|string|string[] $search + * @param ScalarFunction|string|string[] $replace */ - public function strReplace(string|array $search, string|array $replace) : self + public function strReplace(ScalarFunction|string|array $search, ScalarFunction|string|array $replace) : self { return new StrReplace($this, $search, $replace); } /** - * @param string $format - current format of the date that will be used to create DateTimeImmutable instance - * @param \DateTimeZone $timeZone + * @param ScalarFunction|string $format - current format of the date that will be used to create DateTimeImmutable instance */ - public function toDate(string $format = \DateTimeInterface::RFC3339, \DateTimeZone $timeZone = new \DateTimeZone('UTC')) : self + public function toDate(ScalarFunction|string $format = \DateTimeInterface::RFC3339, ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC')) : self { return new ToDate($this, $format, $timeZone); } /** - * @param string $format - current format of the date that will be used to create DateTimeImmutable instance - * @param \DateTimeZone $timeZone + * @param ScalarFunction|string $format - current format of the date that will be used to create DateTimeImmutable instance + * @param \DateTimeZone|ScalarFunction $timeZone */ - public function toDateTime(string $format = 'Y-m-d H:i:s', \DateTimeZone $timeZone = new \DateTimeZone('UTC')) : self + public function toDateTime(ScalarFunction|string $format = 'Y-m-d H:i:s', ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC')) : self { return new ToDateTime($this, $format, $timeZone); } @@ -459,7 +453,7 @@ public function trim(Trim\Type $type = Trim\Type::BOTH, string $characters = " \ * | 2| | | 4| 5| 6| * +--+-----+-----+-----+-----+-----+ */ - public function unpack(array $skipKeys = [], ?string $entryPrefix = null) : self + public function unpack(ScalarFunction|array $skipKeys = [], ScalarFunction|string|null $entryPrefix = null) : self { return new ArrayUnpack($this, $skipKeys, $entryPrefix); } diff --git a/src/core/etl/src/Flow/ETL/Function/Size.php b/src/core/etl/src/Flow/ETL/Function/Size.php index a9d1812e9..5c9e65e12 100644 --- a/src/core/etl/src/Flow/ETL/Function/Size.php +++ b/src/core/etl/src/Flow/ETL/Function/Size.php @@ -8,14 +8,14 @@ final class Size extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref) - { + public function __construct( + private readonly mixed $value + ) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->eval($row); if (\is_string($value)) { return \mb_strlen($value); diff --git a/src/core/etl/src/Flow/ETL/Function/Split.php b/src/core/etl/src/Flow/ETL/Function/Split.php index 8153d7070..048a9fb65 100644 --- a/src/core/etl/src/Flow/ETL/Function/Split.php +++ b/src/core/etl/src/Flow/ETL/Function/Split.php @@ -9,23 +9,22 @@ final class Split extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, + private readonly ScalarFunction|string $value, private readonly ScalarFunction|string $separator, private readonly ScalarFunction|int $limit = PHP_INT_MAX, ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : array|string|null { - $separator = $this->separator instanceof ScalarFunction ? $this->separator->eval($row) : $this->separator; - $limit = $this->limit instanceof ScalarFunction ? $this->limit->eval($row) : $this->limit; + $value = (new Parameter($this->value))->asString($row); + $separator = (new Parameter($this->separator))->asString($row); + $limit = (new Parameter($this->limit))->asInt($row); - $val = $this->ref->eval($row); - - if (!\is_string($val) || !\is_string($separator) || !\is_int($limit) || $limit < 1 || $separator === '') { - return $val; + if ($value === null || $separator === null || $limit === null || $separator === '') { + return null; } - return \explode($separator, $val, $limit); + return \explode($separator, $value, $limit); } } diff --git a/src/core/etl/src/Flow/ETL/Function/Sprintf.php b/src/core/etl/src/Flow/ETL/Function/Sprintf.php index c77f153a3..932bd0736 100644 --- a/src/core/etl/src/Flow/ETL/Function/Sprintf.php +++ b/src/core/etl/src/Flow/ETL/Function/Sprintf.php @@ -9,13 +9,13 @@ final class Sprintf extends ScalarFunctionChain { /** - * @var array + * @var array */ private array $values; public function __construct( - private readonly ScalarFunction $format, - ScalarFunction ...$values + private readonly ScalarFunction|string $format, + ScalarFunction|float|int|string|null ...$values ) { $this->values = $values; } @@ -25,13 +25,14 @@ public function __construct( */ public function eval(Row $row) : ?string { - $format = $this->format->eval($row); + $format = (new Parameter($this->format))->asString($row); + /** * @var array $values */ - $values = \array_map(static fn (ScalarFunction $value) : mixed => $value->eval($row), $this->values); + $values = \array_map(static fn (ScalarFunction|float|int|string|null $value) : mixed => (new Parameter($value))->eval($row), $this->values); - if (!\is_string($format) || \in_array(null, $values, true)) { + if ($format === null || \in_array(null, $values, true)) { return null; } diff --git a/src/core/etl/src/Flow/ETL/Function/StartsWith.php b/src/core/etl/src/Flow/ETL/Function/StartsWith.php index 94c1ff1ad..c7b3131d6 100644 --- a/src/core/etl/src/Flow/ETL/Function/StartsWith.php +++ b/src/core/etl/src/Flow/ETL/Function/StartsWith.php @@ -4,24 +4,22 @@ namespace Flow\ETL\Function; -use function Flow\ETL\DSL\type_string; -use Flow\ETL\PHP\Type\Caster; use Flow\ETL\Row; final class StartsWith extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $haystack, - private readonly ScalarFunction $needle + private readonly ScalarFunction|string $haystack, + private readonly ScalarFunction|string $needle ) { } public function eval(Row $row) : bool { - $haystack = Caster::default()->to(type_string(true))->value($this->haystack->eval($row)); - $needle = Caster::default()->to(type_string(true))->value($this->needle->eval($row)); + $haystack = (new Parameter($this->haystack))->asString($row); + $needle = (new Parameter($this->needle))->asString($row); - if (!\is_string($needle) || !\is_string($haystack)) { + if ($haystack === null || $needle === null) { return false; } diff --git a/src/core/etl/src/Flow/ETL/Function/StrPad.php b/src/core/etl/src/Flow/ETL/Function/StrPad.php index 1c6d743b3..c5f95f3d0 100644 --- a/src/core/etl/src/Flow/ETL/Function/StrPad.php +++ b/src/core/etl/src/Flow/ETL/Function/StrPad.php @@ -4,29 +4,29 @@ namespace Flow\ETL\Function; -use function Flow\ETL\DSL\type_string; -use Flow\ETL\PHP\Type\Caster; use Flow\ETL\Row; final class StrPad extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly int $length, - private readonly string $pad_string = ' ', - private readonly int $type = STR_PAD_RIGHT + private readonly ScalarFunction|string $value, + private readonly ScalarFunction|int $length, + private readonly ScalarFunction|string $padString = ' ', + private readonly ScalarFunction|int $type = STR_PAD_RIGHT ) { } public function eval(Row $row) : mixed { - /** @var null|string $val */ - $val = Caster::default()->to(type_string(true))->value($this->ref->eval($row)); + $value = (new Parameter($this->value))->asString($row); + $length = (new Parameter($this->length))->asInt($row); + $padString = (new Parameter($this->padString))->asString($row); + $type = (new Parameter($this->type))->asInt($row); - if (!\is_string($val)) { + if ($value === null || $length === null || $padString === null || $type === null) { return null; } - return \str_pad($val, $this->length, $this->pad_string, $this->type); + return \str_pad($value, $length, $padString, $type); } } diff --git a/src/core/etl/src/Flow/ETL/Function/StrReplace.php b/src/core/etl/src/Flow/ETL/Function/StrReplace.php index f6c5a34aa..e8ddcf389 100644 --- a/src/core/etl/src/Flow/ETL/Function/StrReplace.php +++ b/src/core/etl/src/Flow/ETL/Function/StrReplace.php @@ -4,32 +4,27 @@ namespace Flow\ETL\Function; -use function Flow\ETL\DSL\type_string; -use Flow\ETL\PHP\Type\Caster; use Flow\ETL\Row; final class StrReplace extends ScalarFunctionChain { - /** - * @param string|string[] $search - * @param string|string[] $replace - */ public function __construct( - private readonly ScalarFunction $ref, - private readonly string|array $search, - private readonly string|array $replace + private readonly ScalarFunction|string $value, + private readonly ScalarFunction|string|array $search, + private readonly ScalarFunction|string|array $replace ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : ?string { - /** @var null|string $val */ - $val = Caster::default()->to(type_string(true))->value($this->ref->eval($row)); + $value = (new Parameter($this->value))->asString($row); + $search = Parameter::oneOf((new Parameter($this->search))->asString($row), (new Parameter($this->search))->asArray($row)); + $replace = Parameter::oneOf((new Parameter($this->replace))->asString($row), (new Parameter($this->replace))->asArray($row)); - if (!\is_string($val)) { + if ($value === null || $search === null || $replace === null) { return null; } - return \str_replace($this->search, $this->replace, $val); + return \str_replace($search, $replace, $value); } } diff --git a/src/core/etl/src/Flow/ETL/Function/ToDate.php b/src/core/etl/src/Flow/ETL/Function/ToDate.php index 2e272f0dc..af0f7693a 100644 --- a/src/core/etl/src/Flow/ETL/Function/ToDate.php +++ b/src/core/etl/src/Flow/ETL/Function/ToDate.php @@ -9,9 +9,9 @@ final class ToDate extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly string $format, - private readonly \DateTimeZone $timeZone = new \DateTimeZone('UTC') + private readonly mixed $value, + private readonly ScalarFunction|string $format, + private readonly ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC') ) { } @@ -20,12 +20,17 @@ public function __construct( */ public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->eval($row); + $format = (new Parameter($this->format))->asString($row); + $timeZone = (new Parameter($this->timeZone))->asInstanceOf($row, \DateTimeZone::class); + + if ($value === null || $format === null || $timeZone === null) { + return null; + } if (\is_object($value)) { if (\is_a($value, \DateTimeImmutable::class) || \is_a($value, \DateTime::class)) { - return $value->setTimezone($this->timeZone)->setTime(0, 0, 0, 0); + return $value->setTimezone($timeZone)->setTime(0, 0, 0, 0); } return null; @@ -33,12 +38,12 @@ public function eval(Row $row) : mixed if (\is_int($value)) { /** @phpstan-ignore-next-line */ - return \DateTimeImmutable::createFromFormat('U', (string) $value, $this->timeZone)->setTime(0, 0, 0, 0); + return \DateTimeImmutable::createFromFormat('U', (string) $value, $timeZone)->setTime(0, 0, 0, 0); } if (\is_string($value)) { /** @phpstan-ignore-next-line */ - return \DateTimeImmutable::createFromFormat($this->format, $value, $this->timeZone)->setTime(0, 0, 0, 0); + return \DateTimeImmutable::createFromFormat($format, $value, $timeZone)->setTime(0, 0, 0, 0); } return null; diff --git a/src/core/etl/src/Flow/ETL/Function/ToDateTime.php b/src/core/etl/src/Flow/ETL/Function/ToDateTime.php index cc360b865..0d8ea6946 100644 --- a/src/core/etl/src/Flow/ETL/Function/ToDateTime.php +++ b/src/core/etl/src/Flow/ETL/Function/ToDateTime.php @@ -9,31 +9,36 @@ final class ToDateTime extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly string $format, - private readonly \DateTimeZone $timeZone = new \DateTimeZone('UTC') + private readonly mixed $value, + private readonly ScalarFunction|string $format, + private readonly ScalarFunction|\DateTimeZone $timeZone = new \DateTimeZone('UTC') ) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->eval($row); + $format = (new Parameter($this->format))->asString($row); + $timeZone = (new Parameter($this->timeZone))->asInstanceOf($row, \DateTimeZone::class); + + if ($value === null || $format === null || $timeZone === null) { + return null; + } if (\is_object($value)) { if (\is_a($value, \DateTimeImmutable::class) || \is_a($value, \DateTime::class)) { - return $value->setTimezone($this->timeZone)->setTime(0, 0, 0, 0); + return $value->setTimezone($timeZone)->setTime(0, 0, 0, 0); } return null; } if (\is_int($value)) { - return \DateTimeImmutable::createFromFormat('U', (string) $value, $this->timeZone); + return \DateTimeImmutable::createFromFormat('U', (string) $value, $timeZone); } if (\is_string($value)) { - return \DateTimeImmutable::createFromFormat($this->format, $value, $this->timeZone); + return \DateTimeImmutable::createFromFormat($format, $value, $timeZone); } return null; diff --git a/src/core/etl/src/Flow/ETL/Function/ToLower.php b/src/core/etl/src/Flow/ETL/Function/ToLower.php index f5ee2b24d..744580bc8 100644 --- a/src/core/etl/src/Flow/ETL/Function/ToLower.php +++ b/src/core/etl/src/Flow/ETL/Function/ToLower.php @@ -8,18 +8,19 @@ final class ToLower extends ScalarFunctionChain { - public function __construct(private ScalarFunction $ref) - { + public function __construct( + private ScalarFunction|string $value + ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : ?string { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->asString($row); + + if ($value === null) { + return null; + } - return match (\gettype($value)) { - 'string' => \mb_strtolower($value), - default => $value, - }; + return \strtolower($value); } } diff --git a/src/core/etl/src/Flow/ETL/Function/ToMoney.php b/src/core/etl/src/Flow/ETL/Function/ToMoney.php deleted file mode 100644 index bc1db6407..000000000 --- a/src/core/etl/src/Flow/ETL/Function/ToMoney.php +++ /dev/null @@ -1,48 +0,0 @@ -to(type_string(true))->value($this->currencyRef->eval($row)); - - if (!\is_string($currency)) { - return null; - } - - if ('' === $currency) { - return null; - } - - $amount = $this->amountRef->eval($row); - - if (!\is_numeric($amount)) { - return null; - } - - return $this->moneyParser->parse((string) $amount, new Currency($currency)); - } -} diff --git a/src/core/etl/src/Flow/ETL/Function/ToTimeZone.php b/src/core/etl/src/Flow/ETL/Function/ToTimeZone.php index 1336a0877..76407cd4f 100644 --- a/src/core/etl/src/Flow/ETL/Function/ToTimeZone.php +++ b/src/core/etl/src/Flow/ETL/Function/ToTimeZone.php @@ -9,23 +9,20 @@ final class ToTimeZone extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $function, - private readonly ScalarFunction $timezone + private readonly ScalarFunction|\DateTimeInterface $value, + private readonly ScalarFunction|\DateTimeZone|string $timezone ) { } public function eval(Row $row) : mixed { - /** - * @var mixed $dateTime - */ - $dateTime = $this->function->eval($row); - /** - * @var mixed $tz - */ - $tz = $this->timezone->eval($row); - - if (!$dateTime instanceof \DateTime && !$dateTime instanceof \DateTimeImmutable) { + $dateTime = (new Parameter($this->value))->asInstanceOf($row, \DateTimeInterface::class); + $tz = Parameter::oneOf( + (new Parameter($this->timezone))->asString($row), + (new Parameter($this->timezone))->asInstanceOf($row, \DateTimeZone::class) + ); + + if ($dateTime === null || $tz === null) { return null; } @@ -39,6 +36,7 @@ public function eval(Row $row) : mixed return null; } + /** @var \DateTime|\DateTimeImmutable $dateTime */ return $dateTime->setTimezone($tz); } } diff --git a/src/core/etl/src/Flow/ETL/Function/ToUpper.php b/src/core/etl/src/Flow/ETL/Function/ToUpper.php index 00c9075e0..5ae3a5b76 100644 --- a/src/core/etl/src/Flow/ETL/Function/ToUpper.php +++ b/src/core/etl/src/Flow/ETL/Function/ToUpper.php @@ -8,14 +8,13 @@ final class ToUpper extends ScalarFunctionChain { - public function __construct(private ScalarFunction $ref) + public function __construct(private readonly ScalarFunction|string $value) { } public function eval(Row $row) : mixed { - /** @var mixed $value */ - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->asString($row); return match (\gettype($value)) { 'string' => \mb_strtoupper($value), diff --git a/src/core/etl/src/Flow/ETL/Function/Trim.php b/src/core/etl/src/Flow/ETL/Function/Trim.php index dbe043450..84726ddbe 100644 --- a/src/core/etl/src/Flow/ETL/Function/Trim.php +++ b/src/core/etl/src/Flow/ETL/Function/Trim.php @@ -4,34 +4,31 @@ namespace Flow\ETL\Function; -use function Flow\ETL\DSL\type_string; use Flow\ETL\Function\Trim\Type; -use Flow\ETL\PHP\Type\Caster; use Flow\ETL\Row; final class Trim extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly Type $type = Type::BOTH, - private readonly string $characters = " \t\n\r\0\x0B" + private readonly ScalarFunction|string $value, + private readonly ScalarFunction|Type $type = Type::BOTH, + private readonly ScalarFunction|string $characters = " \t\n\r\0\x0B" ) { } public function eval(Row $row) : mixed { - /** @var null|string $value */ - $value = Caster::default()->to(type_string(true))->value($this->ref->eval($row)); + $value = (new Parameter($this->value))->asString($row); + $type = (new Parameter($this->type))->asEnum($row, Type::class); + $characters = (new Parameter($this->characters))->asString($row); - if (!\is_string($value)) { + if ($value === null || $type === null || $characters === null) { return null; } - $value = \strtolower($value); - foreach (Type::cases() as $case) { - if ($this->type->name === $case->name) { - return ($case->value)($value, $this->characters); + if ($type->name === $case->name) { + return ($case->value)($value, $characters); } } diff --git a/src/core/etl/src/Flow/ETL/Function/Ulid.php b/src/core/etl/src/Flow/ETL/Function/Ulid.php index 5c1d53090..b2656d6bd 100644 --- a/src/core/etl/src/Flow/ETL/Function/Ulid.php +++ b/src/core/etl/src/Flow/ETL/Function/Ulid.php @@ -13,20 +13,15 @@ final class Ulid extends ScalarFunctionChain { - public function __construct(private readonly ?ScalarFunction $ref = null) + public function __construct(private readonly ScalarFunction|string|null $ref = null) { } public function eval(Row $row) : mixed { - /** @var mixed $param */ - $param = $this->ref?->eval($row); + $param = (new Parameter($this->ref))->asString($row); if (null !== $param) { - if (!\is_string($param)) { - return null; - } - try { return \Symfony\Component\Uid\Ulid::fromString($param); } catch (\InvalidArgumentException) { diff --git a/src/core/etl/src/Flow/ETL/Function/Uuid.php b/src/core/etl/src/Flow/ETL/Function/Uuid.php index a2441599d..348815baa 100644 --- a/src/core/etl/src/Flow/ETL/Function/Uuid.php +++ b/src/core/etl/src/Flow/ETL/Function/Uuid.php @@ -13,8 +13,10 @@ final class Uuid extends ScalarFunctionChain { - private function __construct(private readonly string $uuidVersion, private readonly ?ScalarFunction $ref = null) - { + private function __construct( + private readonly ScalarFunction|string $uuidVersion, + private readonly ScalarFunction|\DateTimeInterface|null $value = null + ) { } public static function uuid4() : self @@ -22,17 +24,21 @@ public static function uuid4() : self return new self('uuid4'); } - public static function uuid7(?ScalarFunction $ref = null) : self + public static function uuid7(ScalarFunction|\DateTimeInterface|null $value = null) : self { - return new self('uuid7', $ref); + return new self('uuid7', $value); } public function eval(Row $row) : mixed { - /** @var mixed $param */ - $param = $this->ref?->eval($row); + $param = Parameter::oneOf( + (new Parameter($this->value))->asString($row), + (new Parameter($this->value))->asInstanceOf($row, \DateTimeInterface::class) + ); + + $uuidVersion = (new Parameter($this->uuidVersion))->asString($row); - return match ($this->uuidVersion) { + return match ($uuidVersion) { 'uuid4' => $this->generateV4(), 'uuid7' => $param instanceof \DateTimeInterface ? $this->generateV7($param) : null, default => null diff --git a/src/core/etl/src/Flow/ETL/Function/When.php b/src/core/etl/src/Flow/ETL/Function/When.php index 760f3cb5b..630170e28 100644 --- a/src/core/etl/src/Flow/ETL/Function/When.php +++ b/src/core/etl/src/Flow/ETL/Function/When.php @@ -9,22 +9,24 @@ final class When extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $ref, - private readonly ScalarFunction $then, - private readonly ?ScalarFunction $else = null + private readonly mixed $condition, + private readonly mixed $then, + private readonly mixed $else = null ) { } public function eval(Row $row) : mixed { - if ($this->ref->eval($row)) { - return $this->then->eval($row); + $condition = (new Parameter($this->condition))->asBoolean($row); + + if ($condition) { + return (new Parameter($this->then))->eval($row); } if ($this->else) { - return $this->else->eval($row); + return (new Parameter($this->else))->eval($row); } - return $this->ref->eval($row); + return null; } } diff --git a/src/core/etl/src/Flow/ETL/Function/XPath.php b/src/core/etl/src/Flow/ETL/Function/XPath.php index cc1715e85..e42435a1e 100644 --- a/src/core/etl/src/Flow/ETL/Function/XPath.php +++ b/src/core/etl/src/Flow/ETL/Function/XPath.php @@ -8,13 +8,20 @@ final class XPath extends ScalarFunctionChain { - public function __construct(private readonly ScalarFunction $ref, private readonly string $path) - { + public function __construct( + private readonly mixed $value, + private readonly ScalarFunction|string $path + ) { } public function eval(Row $row) : \DOMNode|array|null { - $value = $this->ref->eval($row); + $value = (new Parameter($this->value))->asInstanceOf($row, \DOMNode::class); + $path = (new Parameter($this->path))->asString($row); + + if ($value === null || $path === null) { + return null; + } if ($value instanceof \DOMNode && !$value instanceof \DOMDocument) { $dom = new \DOMDocument(); @@ -23,12 +30,8 @@ public function eval(Row $row) : \DOMNode|array|null $value = $dom; } - if (!$value instanceof \DOMDocument) { - return null; - } - $xpath = new \DOMXPath($value); - $result = @$xpath->query($this->path); + $result = @$xpath->query($path); if ($result === false) { return null; diff --git a/src/core/etl/src/Flow/ETL/PHP/Type/TypeFactory.php b/src/core/etl/src/Flow/ETL/PHP/Type/TypeFactory.php index 79c8a97f5..d3c83f8d4 100644 --- a/src/core/etl/src/Flow/ETL/PHP/Type/TypeFactory.php +++ b/src/core/etl/src/Flow/ETL/PHP/Type/TypeFactory.php @@ -42,4 +42,18 @@ public static function fromArray(array $data) : Type default => throw new InvalidArgumentException("Unknown type '{$data['type']}'"), }; } + + /** + * @throws InvalidArgumentException + */ + public static function fromString(string $name) : Type + { + return match (\mb_strtolower($name)) { + 'int','integer' => self::fromArray(['type' => 'scalar', 'scalar_type' => 'integer']), + 'float' => self::fromArray(['type' => 'scalar', 'scalar_type' => 'float']), + 'string' => self::fromArray(['type' => 'scalar', 'scalar_type' => 'string']), + 'bool','boolean' => self::fromArray(['type' => 'scalar', 'scalar_type' => 'boolean']), + default => self::fromArray(['type' => $name]), + }; + } } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/DataFrame/PartitioningTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/DataFrame/PartitioningTest.php index edf166a27..04237caa8 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/DataFrame/PartitioningTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/DataFrame/PartitioningTest.php @@ -220,8 +220,8 @@ public function test_pruning_single_partition() : void $rows = df() ->read(from_text(__DIR__ . '/Fixtures/Partitioning/multi_partition_pruning_test/year=*/month=*/day=*/*.txt')) ->filterPartitions( - ref('year') - ->concat(lit('-'), ref('month')->strPadLeft(2, '0'), lit('-'), ref('day')->strPadLeft(2, '0')) + ref('year')->cast('string') + ->concat(lit('-'), ref('month')->cast('string')->strPadLeft(2, '0'), lit('-'), ref('day')->cast('string')->strPadLeft(2, '0')) ->cast('date') ->greaterThanEqual(lit(new \DateTimeImmutable('2023-01-01'))) ) diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayGetCollectionTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayGetCollectionTest.php index 7dd9529df..799bd397f 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayGetCollectionTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayGetCollectionTest.php @@ -26,7 +26,7 @@ public function test_array_get_collection() : void ] ) ) - ->withEntry('result', ref('array')->arrayGetCollection('a', 'c')) + ->withEntry('result', ref('array')->arrayGetCollection(['a', 'c'])) ->drop('array') ->write(to_memory($memory = new ArrayMemory())) ->run(); diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayExistsTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayPathExistsTest.php similarity index 52% rename from src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayExistsTest.php rename to src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayPathExistsTest.php index 2067bfe39..4bae90941 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayExistsTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArrayPathExistsTest.php @@ -9,9 +9,34 @@ use Flow\ETL\Memory\ArrayMemory; use PHPUnit\Framework\TestCase; -final class ArrayExistsTest extends TestCase +final class ArrayPathExistsTest extends TestCase { - public function test_array_exists() : void + public function test_array_path_exists() : void + { + (new Flow()) + ->read( + from_array( + [ + ['id' => 1, 'array' => ['a' => 1, 'b' => 2, 'c' => 3]], + ['id' => 2], + ] + ) + ) + ->withEntry('has_array', ref('array')->arrayPathExists('a')) + ->drop('array') + ->write(to_memory($memory = new ArrayMemory())) + ->run(); + + self::assertSame( + [ + ['id' => 1, 'has_array' => true], + ['id' => 2, 'has_array' => false], + ], + $memory->dump() + ); + } + + public function test_array_path_function_exists() : void { (new Flow()) ->read( diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArraySortTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArraySortTest.php index 8eaad443a..268f10c20 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArraySortTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ArraySortTest.php @@ -6,6 +6,7 @@ use function Flow\ETL\DSL\{array_sort, from_array, optional, ref, to_memory}; use Flow\ETL\Flow; +use Flow\ETL\Function\ArraySort\Sort; use Flow\ETL\Memory\ArrayMemory; use PHPUnit\Framework\TestCase; @@ -23,7 +24,7 @@ public function test_array_sort() : void ) ) - ->withEntry('array', optional(array_sort(ref('array'), 'ksort'))) + ->withEntry('array', optional(array_sort(ref('array'), Sort::ksort))) ->write(to_memory($memory = new ArrayMemory())) ->run(); diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/BinaryComparisonsTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/BinaryComparisonsTest.php index be89c74e3..a2af9141b 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/BinaryComparisonsTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/BinaryComparisonsTest.php @@ -7,7 +7,6 @@ use function Flow\ETL\DSL\{from_array, lit, ref, to_memory, when}; use Flow\ETL\Flow; use Flow\ETL\Memory\ArrayMemory; -use Flow\ETL\Row\Entry\StringEntry; use PHPUnit\Framework\TestCase; final class BinaryComparisonsTest extends TestCase @@ -76,7 +75,7 @@ public function test_all_comparisons() : void ) ->withEntry( 'type', - when(ref('a')->isType(StringEntry::class), lit(true), lit(false)) + when(ref('a')->isType('string'), lit(true), lit(false)) ) ->drop('array') ->write(to_memory($memory = new ArrayMemory())) diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ConcatTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ConcatTest.php index 1a445b598..5b03023d1 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ConcatTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ConcatTest.php @@ -46,7 +46,7 @@ public function test_concat_on_stringable_value() : void ] ) ) - ->withEntry('concat', concat(ref('id'), lit('-'), array_get(ref('array'), 'field'))) + ->withEntry('concat', concat(ref('id'), '-', array_get(ref('array'), 'field'))) ->drop('array') ->write(to_memory($memory = new ArrayMemory())) ->run(); diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/SplitTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/SplitTest.php index 21fd8ce63..071050596 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/SplitTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/SplitTest.php @@ -49,7 +49,7 @@ public function test_split_on_non_string_value() : void self::assertSame( [ - ['key' => 1, 'split' => 1], + ['key' => 1, 'split' => null], ], $memory->dump() ); diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StartsWithTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StartsWithTest.php index 02f528e4d..127fdd8d4 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StartsWithTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StartsWithTest.php @@ -49,7 +49,7 @@ public function test_starts_with_on_non_string_key() : void self::assertSame( [ - ['id' => 1, 'starts_with' => true], + ['id' => 1, 'starts_with' => false], ], $memory->dump() ); @@ -71,7 +71,7 @@ public function test_starts_with_on_non_string_value() : void self::assertSame( [ - ['id' => '1', 'starts_with' => true], + ['id' => '1', 'starts_with' => false], ], $memory->dump() ); diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrPadTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrPadTest.php index e881221df..9985095ec 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrPadTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrPadTest.php @@ -32,26 +32,4 @@ public function test_strpad() : void $memory->dump() ); } - - public function test_strpad_on_non_string_key() : void - { - (new Flow()) - ->read( - from_array( - [ - ['id' => 1], - ] - ) - ) - ->withEntry('strpad', ref('id')->strPad(10)) - ->write(to_memory($memory = new ArrayMemory())) - ->run(); - - self::assertSame( - [ - ['id' => 1, 'strpad' => '1 '], - ], - $memory->dump() - ); - } } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrReplaceTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrReplaceTest.php index 2d15b487c..ac1eed679 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrReplaceTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/StrReplaceTest.php @@ -32,26 +32,4 @@ public function test_str_replace() : void $memory->dump() ); } - - public function test_str_replace_on_non_string_key() : void - { - (new Flow()) - ->read( - from_array( - [ - ['id' => 1], - ] - ) - ) - ->withEntry('str_replace', ref('id')->strReplace('', '')) - ->write(to_memory($memory = new ArrayMemory())) - ->run(); - - self::assertSame( - [ - ['id' => 1, 'str_replace' => '1'], - ], - $memory->dump() - ); - } } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToLowerTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToLowerTest.php index 2b5bb2737..16efa8d97 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToLowerTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToLowerTest.php @@ -32,26 +32,4 @@ public function test_to_lower() : void $memory->dump() ); } - - public function test_to_lower_on_non_string_key() : void - { - (new Flow()) - ->read( - from_array( - [ - ['id' => 1], - ] - ) - ) - ->withEntry('to_lower', ref('id')->lower()) - ->write(to_memory($memory = new ArrayMemory())) - ->run(); - - self::assertSame( - [ - ['id' => 1, 'to_lower' => 1], - ], - $memory->dump() - ); - } } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToUpperTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToUpperTest.php index df4fd7d8e..ee9c4781a 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToUpperTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/ToUpperTest.php @@ -32,26 +32,4 @@ public function test_to_upper() : void $memory->dump() ); } - - public function test_to_upper_on_non_string_key() : void - { - (new Flow()) - ->read( - from_array( - [ - ['id' => 1], - ] - ) - ) - ->withEntry('to_upper', ref('id')->upper()) - ->write(to_memory($memory = new ArrayMemory())) - ->run(); - - self::assertSame( - [ - ['id' => 1, 'to_upper' => 1], - ], - $memory->dump() - ); - } } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/TrimTest.php b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/TrimTest.php index 60cdb325c..efb52fa5a 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/TrimTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Integration/Function/TrimTest.php @@ -78,28 +78,6 @@ public function test_trim_left() : void ); } - public function test_trim_on_non_string_key() : void - { - (new Flow()) - ->read( - from_array( - [ - ['id' => 1], - ] - ) - ) - ->withEntry('trim', ref('id')->trim()) - ->write(to_memory($memory = new ArrayMemory())) - ->run(); - - self::assertSame( - [ - ['id' => 1, 'trim' => '1'], - ], - $memory->dump() - ); - } - public function test_trim_right() : void { (new Flow()) diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArrayGetCollectionTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArrayGetCollectionTest.php index 8c745c4df..b81f3d090 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArrayGetCollectionTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArrayGetCollectionTest.php @@ -16,7 +16,7 @@ public function test_for_not_array_entry() : void int_entry('invalid_entry', 1), ); - self::assertNull(array_get_collection(ref('invalid_entry'), 'id')->eval($row)); + self::assertNull(array_get_collection(ref('invalid_entry'), ['id'])->eval($row)); } public function test_getting_keys_from_simple_array() : void @@ -33,7 +33,7 @@ public function test_getting_keys_from_simple_array() : void ), ); - self::assertNull(array_get_collection(ref('array_entry'), 'id', 'status')->eval($row)); + self::assertNull(array_get_collection(ref('array_entry'), ['id'], 'status')->eval($row)); } public function test_getting_specific_keys_from_collection_of_array() : void @@ -63,7 +63,7 @@ public function test_getting_specific_keys_from_collection_of_array() : void ['id' => 1, 'status' => 'PENDING'], ['id' => 2, 'status' => 'NEW'], ], - array_get_collection(ref('array_entry'), 'id', 'status')->eval($row) + array_get_collection(ref('array_entry'), ['id', 'status'])->eval($row) ); } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArraySortTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArraySortTest.php index 73de1ae26..b3ee1d03b 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArraySortTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ArraySortTest.php @@ -5,6 +5,7 @@ namespace Flow\ETL\Tests\Unit\Function; use function Flow\ETL\DSL\{array_entry, ref, str_entry}; +use Flow\ETL\Function\ArraySort\Sort; use Flow\ETL\Row; use PHPUnit\Framework\TestCase; @@ -13,8 +14,8 @@ final class ArraySortTest extends TestCase public function test_sorting_big_arrays() : void { self::assertSame( - ref('array')->arraySort('sort')->eval(Row::create(array_entry('array', \json_decode($this->jsonDifferentOrder(), true, 512, JSON_THROW_ON_ERROR)))), - ref('array')->arraySort('sort')->eval(Row::create(array_entry('array', \json_decode($this->json(), true, 512, JSON_THROW_ON_ERROR)))) + ref('array')->arraySort()->eval(Row::create(array_entry('array', \json_decode($this->jsonDifferentOrder(), true, 512, JSON_THROW_ON_ERROR)))), + ref('array')->arraySort()->eval(Row::create(array_entry('array', \json_decode($this->json(), true, 512, JSON_THROW_ON_ERROR)))) ); } @@ -30,7 +31,7 @@ public function test_sorting_nested_array_using_asort_algo() : void ], ], ], - ref('array')->arraySort('asort')->eval(Row::create( + ref('array')->arraySort(Sort::asort)->eval(Row::create( array_entry( 'array', [ @@ -59,7 +60,7 @@ public function test_sorting_nested_associative_array() : void 'g' => 'h', ], ], - ref('array')->arraySort('ksort')->eval(Row::create( + ref('array')->arraySort(Sort::ksort)->eval(Row::create( array_entry( 'array', [ diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/BinaryComparisonsTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/BinaryComparisonsTest.php index 6aa63f71e..0b1d1a630 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/BinaryComparisonsTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/BinaryComparisonsTest.php @@ -4,10 +4,9 @@ namespace Flow\ETL\Tests\Unit\Function; -use function Flow\ETL\DSL\{array_entry, datetime_entry, int_entry, lit, ref, str_entry}; +use function Flow\ETL\DSL\{array_entry, datetime_entry, int_entry, lit, ref, str_entry, type_string}; use Flow\ETL\Function\{Contains, EndsWith, Equals, GreaterThan, GreaterThanEqual, IsIn, IsNotNull, IsNotNumeric, IsNull, IsNumeric, IsType, LessThan, LessThanEqual, NotEquals, NotSame, Same, StartsWith}; use Flow\ETL\Row; -use Flow\ETL\Row\Entry\{IntegerEntry, StringEntry}; use PHPUnit\Framework\TestCase; final class BinaryComparisonsTest extends TestCase @@ -91,13 +90,13 @@ public function test_is_type() : void int_entry('b', null), ); - self::assertTrue((new IsType(ref('a'), IntegerEntry::class, StringEntry::class))->eval($row)); - self::assertFalse((new IsType(ref('a'), StringEntry::class))->eval($row)); + self::assertTrue((new IsType(ref('a'), 'integer', 'string'))->eval($row)); + self::assertFalse((new IsType(ref('a'), type_string()))->eval($row)); } public function test_is_type_with_non_existing_type_class() : void { - $this->expectExceptionMessage('"aaa" is not valid Entry Type class'); + $this->expectExceptionMessage('Unknown type \'aaa\''); $row = Row::create( int_entry('a', 100), diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CallMethodTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CallMethodTest.php index 60e3842ec..4a448e68d 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CallMethodTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CallMethodTest.php @@ -23,7 +23,7 @@ public function test_call_method() : void call_method( ref('object'), ref('method'), - ref('method_param'), + [ref('method_param')], )->eval($row) ); } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/NumberFormatTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/NumberFormatTest.php index 34208ec4b..85498b007 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/NumberFormatTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/NumberFormatTest.php @@ -93,26 +93,4 @@ public function test_number_format_on_non_int_entry() : void ) ); } - - public function test_number_format_on_numeric_entry() : void - { - $expression = new NumberFormat( - ref('value'), - ref('decimals'), - ref('decimal_separator'), - ref('thousands_separator') - ); - - self::assertSame( - '1,234.57', - $expression->eval( - Row::create( - str_entry('value', '1234.5678'), - int_entry('decimals', 2), - str_entry('decimal_separator', '.'), - str_entry('thousands_separator', ',') - ) - ) - ); - } } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/SplitTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/SplitTest.php index a01a7246d..8b8c95495 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/SplitTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/SplitTest.php @@ -12,8 +12,7 @@ final class SplitTest extends TestCase { public function test_split_not_string() : void { - self::assertSame( - 123, + self::assertNull( split(lit(123), ',')->eval(Row::create()) ); } diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrPadTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrPadTest.php index 8ba32ce96..a4ad2b50d 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrPadTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrPadTest.php @@ -4,20 +4,12 @@ namespace Flow\ETL\Tests\Unit\Function; -use function Flow\ETL\DSL\{int_entry, ref, str_entry}; +use function Flow\ETL\DSL\{ref, str_entry}; use Flow\ETL\Row; use PHPUnit\Framework\TestCase; final class StrPadTest extends TestCase { - public function test_str_pad_on_non_string_value() : void - { - self::assertSame( - '-1000', - ref('value')->strPad(5, '-', \STR_PAD_LEFT)->eval(Row::create(int_entry('value', 1000))), - ); - } - public function test_str_pad_on_valid_string() : void { self::assertSame( diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrReplaceTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrReplaceTest.php index eb2955004..6bb4342f2 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrReplaceTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/StrReplaceTest.php @@ -4,20 +4,12 @@ namespace Flow\ETL\Tests\Unit\Function; -use function Flow\ETL\DSL\{int_entry, ref, str_entry}; +use function Flow\ETL\DSL\{ref, str_entry}; use Flow\ETL\Row; use PHPUnit\Framework\TestCase; final class StrReplaceTest extends TestCase { - public function test_str_replace_on_non_string_value() : void - { - self::assertSame( - '1000', - ref('value')->strReplace('test', '1')->eval(Row::create(int_entry('value', 1000))), - ); - } - public function test_str_replace_on_valid_string() : void { self::assertSame( diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToLowerTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToLowerTest.php index 3875a6e84..0041f6d80 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToLowerTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToLowerTest.php @@ -10,14 +10,6 @@ final class ToLowerTest extends TestCase { - public function test_int_to_lower() : void - { - self::assertSame( - 1, - lower(lit(1))->eval(Row::create()) - ); - } - public function test_string_to_lower() : void { self::assertSame( diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToMoneyTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToMoneyTest.php deleted file mode 100644 index 43dea4dba..000000000 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToMoneyTest.php +++ /dev/null @@ -1,62 +0,0 @@ -eval($row) - ); - } - - public function test_money_amount_float() : void - { - $row = Row::create(float_entry('a', 19.90), str_entry('b', 'USD')); - - self::assertEquals( - new Money('1990', new Currency('USD')), - (new ToMoney(ref('a'), ref('b')))->eval($row) - ); - } - - public function test_money_amount_integer() : void - { - $row = Row::create(int_entry('a', 19), str_entry('b', 'USD')); - - self::assertEquals( - new Money('1900', new Currency('USD')), - (new ToMoney(ref('a'), ref('b')))->eval($row) - ); - } - - public function test_non_numeric_money_amount() : void - { - $row = Row::create(bool_entry('a', false), str_entry('b', null)); - - self::assertNull( - (new ToMoney(ref('a'), ref('b')))->eval($row) - ); - } - - public function test_null_currency() : void - { - $row = Row::create(str_entry('a', '19.90'), str_entry('b', null)); - - self::assertNull( - (new ToMoney(ref('a'), ref('b')))->eval($row) - ); - } -} diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToUpperTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToUpperTest.php index f3b4bafd1..b72aa5fa4 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToUpperTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/ToUpperTest.php @@ -10,14 +10,6 @@ final class ToUpperTest extends TestCase { - public function test_int_to_upper() : void - { - self::assertSame( - 1, - upper(lit(1))->eval(Row::create()) - ); - } - public function test_string_to_upper() : void { self::assertSame( diff --git a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/TrimTest.php b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/TrimTest.php index cd5538c6b..3f9ea5746 100644 --- a/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/TrimTest.php +++ b/src/core/etl/tests/Flow/ETL/Tests/Unit/Function/TrimTest.php @@ -4,7 +4,7 @@ namespace Flow\ETL\Tests\Unit\Function; -use function Flow\ETL\DSL\{int_entry, ref, str_entry}; +use function Flow\ETL\DSL\{ref, str_entry}; use Flow\ETL\Function\Trim\Type; use Flow\ETL\Row; use PHPUnit\Framework\TestCase; @@ -19,14 +19,6 @@ public function test_trim_both_valid_string() : void ); } - public function test_trim_integer() : void - { - self::assertSame( - '1', - ref('integer')->trim()->eval(Row::create(int_entry('integer', 1))) - ); - } - public function test_trim_left_valid_string() : void { self::assertSame( diff --git a/web/landing/assets/styles/app.css b/web/landing/assets/styles/app.css index 877fe5a18..d2ca6eb59 100644 --- a/web/landing/assets/styles/app.css +++ b/web/landing/assets/styles/app.css @@ -33,7 +33,7 @@ code { @apply py-10 px-2 sm:px-4 mx-auto max-w-screen-xl; } -#blog-post hr, p, pre, ul { +#blog-post hr, p, pre, ul, h2, h3 { @apply mb-3; } diff --git a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/post.html.twig b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/post.html.twig index 95de0f09b..106029627 100644 --- a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/post.html.twig +++ b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/post.html.twig @@ -31,7 +31,7 @@

{% apply escape %}{% include template_folder ~ '/power.php' %}{% endapply %}

- Let's start by analyzing the function constructor. We can notice that the arguments passed to the constructor are two other scalar functions. + Let's start by analyzing the function constructor. We can notice that the arguments passed to the constructor are two other can also be scalar functions. This simple trick allows us to refer to values from different cells using the ref function.

@@ -93,9 +93,18 @@

  • what if false
  • - If we look at the implementation of this function, we'll notice that all its arguments are also scalar functions. This allows us to build very complicated nested conditions. + If we look at the implementation of this function, we'll notice that all its arguments are mixed (so we can provide literal values or scalar functions). This allows us to build very complicated nested conditions.

    {% apply escape %}{% include template_folder ~ '/when-function.php' %}{% endapply %}
    +

    References

    + {% endblock %} diff --git a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power-eval.php b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power-eval.php index da57d0db2..cee22c395 100644 --- a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power-eval.php +++ b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power-eval.php @@ -1,15 +1,15 @@ -public function eval(Row $row) : mixed +public function eval(Row $row) : float|int|null { // Retrieving parameters - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); // Validating parameters - if ($right === 0) { + if ($left === null || $right === null) { return null; } - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($right === 0) { return null; } diff --git a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power.php b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power.php index e12b3d45f..817accef2 100644 --- a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power.php +++ b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/power.php @@ -9,21 +9,21 @@ final class Power extends ScalarFunctionChain { public function __construct( - private readonly ScalarFunction $leftRef, - private readonly ScalarFunction $rightRef + private readonly ScalarFunction|int|float $left, + private readonly ScalarFunction|int|float $right ) { } - public function eval(Row $row) : mixed + public function eval(Row $row) : float|int|null { - $left = $this->leftRef->eval($row); - $right = $this->rightRef->eval($row); + $left = (new Parameter($this->left))->asNumber($row); + $right = (new Parameter($this->right))->asNumber($row); - if ($right === 0) { + if ($left === null || $right === null) { return null; } - if (!\is_numeric($left) || !\is_numeric($right)) { + if ($right === 0) { return null; } diff --git a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/when-function.php b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/when-function.php index a3ca8ea8a..f9350c930 100644 --- a/web/landing/templates/blog/posts/2024-08-08/scalar-functions/when-function.php +++ b/web/landing/templates/blog/posts/2024-08-08/scalar-functions/when-function.php @@ -1,4 +1,4 @@ -function when(ScalarFunction $ref, ScalarFunction $then, ?ScalarFunction $else = null) : When +function when(mixed $condition, mixed $then, mixed $else = null) : When { - return new When($ref, $then, $else); + return new When($condition, $then, $else); } \ No newline at end of file