From 912edb9e17cad216ecd8c16e902bae437a51a040 Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 01:26:30 +0200 Subject: [PATCH 01/19] fix: backticks + refactor --- docs/Extractors/Table.md | 2 +- src/Database/Query.php | 115 +++++++++++--------- src/Database/WhereBoolean.php | 18 +++ src/Database/WhereOperator.php | 25 +++++ src/Database/WhereStatement.php | 23 ++++ src/Database/WhereType.php | 19 ++++ tests/Unit/Database/QueryTest.php | 20 ++-- tests/Unit/Extractors/AggregatorTest.php | 2 + tests/Unit/Extractors/DateDimensionTest.php | 2 +- 9 files changed, 164 insertions(+), 62 deletions(-) create mode 100644 src/Database/WhereBoolean.php create mode 100644 src/Database/WhereOperator.php create mode 100644 src/Database/WhereStatement.php create mode 100644 src/Database/WhereType.php diff --git a/docs/Extractors/Table.md b/docs/Extractors/Table.md index 29130feb..debbcdc8 100644 --- a/docs/Extractors/Table.md +++ b/docs/Extractors/Table.md @@ -40,7 +40,7 @@ $options = [Table::CONNECTION => 'app']; Array of conditions, each condition is either: - `key` equals `value` , or -- `key` _comparesTo_ `value` (comparesTo can be: =, <, <=, =>, >, or <>). +- `key` _comparesTo_ `value` (comparesTo can be: =, <, <=, >=, >, or <>). If you need more flexibility in the query creation, you may use the [Query extractor](Query.md). diff --git a/src/Database/Query.php b/src/Database/Query.php index 65f56b8e..090adfdd 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -76,11 +76,14 @@ public function getBindings(): array * * @return $this */ - public function select(string $table, array $columns = ['*']): Query + public function select(string $table, ?array $columns = null): Query { - $columns = $this->implode($columns); - $this->query[] = "select $columns from $table"; + $columns = \is_null($columns) + ? '*' + : $this->implode($columns, '`{column}`'); + + $this->query[] = "SELECT $columns FROM `$table`"; return $this; } @@ -96,9 +99,9 @@ public function insert(string $table, array $columns): Query $values = $this->implode($columns, '?'); - $columns = $this->implode(array_keys($columns)); + $columns = $this->implode(array_keys($columns), '`{column}`'); - $this->query[] = "insert into $table ($columns) values ($values)"; + $this->query[] = "INSERT INTO `$table` ($columns) VALUES ($values)"; return $this; } @@ -112,9 +115,12 @@ public function update(string $table, array $columns): Query { $this->bindings = array_merge($this->bindings, array_values($columns)); - $columns = $this->implode(array_keys($columns), '{column} = ?'); + $columns = $this->implode( + array_keys($columns), + '`{column}` = ?' + ); - $this->query[] = "update $table set $columns"; + $this->query[] = "UPDATE `$table` SET $columns"; return $this; } @@ -126,7 +132,7 @@ public function update(string $table, array $columns): Query */ public function delete(string $table): Query { - $this->query[] = "delete from {$table}"; + $this->query[] = "DELETE FROM `$table`"; return $this; } @@ -139,14 +145,20 @@ public function delete(string $table): Query public function where(array $columns): Query { foreach ($columns as $column => $value) { - $condition = ['type' => 'Where', 'column' => $column, 'boolean' => 'and']; + $condition = [ + WhereStatement::TYPE => WhereType::Where, + WhereStatement::COLUMN => $column, + WhereStatement::BOOLEAN => WhereBoolean::And, + ]; + if (is_scalar($value)) { - $condition['operator'] = '='; - $condition['value'] = $value; + $condition[WhereStatement::OPERATOR] = WhereOperator::Equal; + $condition[WhereStatement::VALUE] = $value; } else { - $condition['operator'] = $value[0]; - $condition['value'] = $value[1]; + $condition[WhereStatement::OPERATOR] = WhereOperator::from($value[0]); + $condition[WhereStatement::VALUE] = $value[1]; } + $this->wheres[] = $condition; } @@ -160,23 +172,26 @@ public function where(array $columns): Query * * @return $this */ - public function whereIn($column, array $values, string $operator = 'in'): Query - { + public function whereIn( + $column, + array $values, + WhereOperator $operator = WhereOperator::In + ): Query { if (is_string($column)) { $this->wheres[] = [ - 'type' => 'WhereIn', - 'column' => $column, - 'values' => $values, - 'operator' => $operator, - 'boolean' => 'and', + WhereStatement::TYPE => WhereType::WhereIn, + WhereStatement::COLUMN => $column, + WhereStatement::MULTIPLE_VALUES => $values, + WhereStatement::OPERATOR => $operator, + WhereStatement::BOOLEAN => WhereBoolean::And, ]; } else { $this->wheres[] = [ - 'type' => 'CompositeWhereIn', - 'columns' => $column, - 'values' => $values, - 'operator' => $operator, - 'boolean' => 'and', + WhereStatement::TYPE => WhereType::CompositeWhereIn, + WhereStatement::MULTIPLE_COLUMNS => $column, + WhereStatement::MULTIPLE_VALUES => $values, + WhereStatement::OPERATOR => $operator, + WhereStatement::BOOLEAN => WhereBoolean::And, ]; } @@ -192,7 +207,7 @@ public function whereIn($column, array $values, string $operator = 'in'): Query */ public function whereNotIn($column, array $values): Query { - return $this->whereIn($column, $values, 'not in'); + return $this->whereIn($column, $values, WhereOperator::NotIn); } /** @@ -204,13 +219,13 @@ protected function compileWheres(): void return; } - $this->query[] = 'where'; + $this->query[] = 'WHERE'; foreach ($this->wheres as $index => $condition) { - $method = 'compile' . $condition['type']; + $method = 'compile' . $condition[WhereStatement::TYPE]->value; if (0 == $index) { - $condition['boolean'] = ''; + $condition[WhereStatement::BOOLEAN] = WhereBoolean::Nothing; } $this->query[] = trim($this->{$method}($condition)); @@ -223,14 +238,14 @@ protected function compileWheres(): void protected function compileWhere(array $where): string { // All these if, empty, are here to clean the legacy code before the fork. See the git history. - $boolean = array_key_exists('boolean', $where) ? $where['boolean'] : null; - $column = array_key_exists('column', $where) ? $where['column'] : null; - $operator = array_key_exists('operator', $where) ? $where['operator'] : null; - $value = array_key_exists('value', $where) ? $where['value'] : null; + $boolean = array_key_exists(WhereStatement::BOOLEAN, $where) ? $where[WhereStatement::BOOLEAN]->value : null; + $column = array_key_exists(WhereStatement::COLUMN, $where) ? $where[WhereStatement::COLUMN] : null; + $operator = array_key_exists(WhereStatement::OPERATOR, $where) ? $where[WhereStatement::OPERATOR]->value : null; + $value = array_key_exists(WhereStatement::VALUE, $where) ? $where[WhereStatement::VALUE] : null; $this->bindings[] = $value; - return "$boolean $column $operator ?"; + return "$boolean `$column` $operator ?"; } /** @@ -239,34 +254,34 @@ protected function compileWhere(array $where): string protected function compileWhereIn(array $where): string { // All these if, empty, are here to clean the legacy code before the fork. See the git history. - $boolean = array_key_exists('boolean', $where) ? $where['boolean'] : null; - $column = array_key_exists('column', $where) ? $where['column'] : null; - $operator = array_key_exists('operator', $where) ? $where['operator'] : null; - $values = array_key_exists('values', $where) ? $where['values'] : null; + $boolean = array_key_exists(WhereStatement::BOOLEAN, $where) ? $where[WhereStatement::BOOLEAN]->value : null; + $column = array_key_exists(WhereStatement::COLUMN, $where) ? $where[WhereStatement::COLUMN] : null; + $operator = array_key_exists(WhereStatement::OPERATOR, $where) ? $where[WhereStatement::OPERATOR]->value : null; + $multipleValues = array_key_exists(WhereStatement::MULTIPLE_VALUES, $where) ? $where[WhereStatement::MULTIPLE_VALUES] : null; - $this->bindings = array_merge($this->bindings, $values); + $this->bindings = array_merge($this->bindings, $multipleValues); - $parameters = $this->implode($values, '?'); + $parameters = $this->implode($multipleValues, '?'); - return "$boolean $column $operator ($parameters)"; + return "$boolean `$column` $operator ($parameters)"; } /** - * Compile the composite where in statement. + * Compile the composite where in statecolumnment. */ protected function compileCompositeWhereIn(array $where): string { // All these if, empty, are here to clean the legacy code before the fork. See the git history. - $boolean = array_key_exists('boolean', $where) ? $where['boolean'] : null; - $columns = array_key_exists('columns', $where) ? $where['columns'] : null; - $operator = array_key_exists('operator', $where) ? $where['operator'] : null; - $values = array_key_exists('values', $where) ? $where['values'] : null; + $boolean = array_key_exists(WhereStatement::BOOLEAN, $where) ? $where[WhereStatement::BOOLEAN]->value : null; + $multipleColumns = array_key_exists(WhereStatement::MULTIPLE_COLUMNS, $where) ? $where[WhereStatement::MULTIPLE_COLUMNS] : null; + $operator = array_key_exists(WhereStatement::OPERATOR, $where) ? $where[WhereStatement::OPERATOR]->value : null; + $multipleValues = array_key_exists(WhereStatement::MULTIPLE_VALUES, $where) ? $where[WhereStatement::MULTIPLE_VALUES] : null; - sort($columns); + sort($multipleColumns); $parameters = []; - foreach ($values as $value) { + foreach ($multipleValues as $value) { ksort($value); $this->bindings = array_merge($this->bindings, array_values($value)); @@ -276,9 +291,9 @@ protected function compileCompositeWhereIn(array $where): string $parameters = $this->implode($parameters); - $columns = $this->implode($columns); + $multipleColumns = $this->implode($multipleColumns, '`{column}`'); - return "$boolean ($columns) $operator ($parameters)"; + return "$boolean ($multipleColumns) $operator ($parameters)"; } /** diff --git a/src/Database/WhereBoolean.php b/src/Database/WhereBoolean.php new file mode 100644 index 00000000..9b76058a --- /dev/null +++ b/src/Database/WhereBoolean.php @@ -0,0 +1,18 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +enum WhereBoolean: string +{ + case And = 'AND'; + case Nothing = ''; +} diff --git a/src/Database/WhereOperator.php b/src/Database/WhereOperator.php new file mode 100644 index 00000000..fd66ca8d --- /dev/null +++ b/src/Database/WhereOperator.php @@ -0,0 +1,25 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +enum WhereOperator: string +{ + case Equal = '='; + case Less = '<'; + case LessOrEqual = '<='; + case Greater = '>'; + case GreaterOrEqual = '>='; + case NotEqual = '<>'; + case NotEqualBis = '!='; + case In = 'IN'; + case NotIn = 'NOT IN'; +} diff --git a/src/Database/WhereStatement.php b/src/Database/WhereStatement.php new file mode 100644 index 00000000..06c26ff8 --- /dev/null +++ b/src/Database/WhereStatement.php @@ -0,0 +1,23 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +class WhereStatement +{ + const TYPE = 'type'; + const BOOLEAN = 'boolean'; + const MULTIPLE_COLUMNS = 'columns'; + const COLUMN = 'column'; + const OPERATOR = 'operator'; + const MULTIPLE_VALUES = 'values'; + const VALUE = 'value'; +} diff --git a/src/Database/WhereType.php b/src/Database/WhereType.php new file mode 100644 index 00000000..ca8474bf --- /dev/null +++ b/src/Database/WhereType.php @@ -0,0 +1,19 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +enum WhereType: string +{ + case Where = 'Where'; + case WhereIn = 'WhereIn'; + case CompositeWhereIn = 'CompositeWhereIn'; +} diff --git a/tests/Unit/Database/QueryTest.php b/tests/Unit/Database/QueryTest.php index 618dcc02..729e935d 100644 --- a/tests/Unit/Database/QueryTest.php +++ b/tests/Unit/Database/QueryTest.php @@ -22,12 +22,12 @@ public function select(): void $query = new Query($this->createMock('PDO')); $query->select('users'); - static::assertEquals('select * from users', $query->toSql()); + static::assertEquals('SELECT * FROM `users`', $query->toSql()); $query = new Query($this->createMock('PDO')); $query->select('users', ['name', 'email']); - static::assertEquals('select name, email from users', $query->toSql()); + static::assertEquals('SELECT `name`, `email` FROM `users`', $query->toSql()); } /** @test */ @@ -36,7 +36,7 @@ public function insert(): void $query = new Query($this->createMock('PDO')); $query->insert('users', ['name' => 'Jane Doe', 'email' => 'janedoe@example.com']); - static::assertEquals('insert into users (name, email) values (?, ?)', $query->toSql()); + static::assertEquals('INSERT INTO `users` (`name`, `email`) VALUES (?, ?)', $query->toSql()); static::assertEquals(['Jane Doe', 'janedoe@example.com'], $query->getBindings()); } @@ -46,7 +46,7 @@ public function update(): void $query = new Query($this->createMock('PDO')); $query->update('users', ['name' => 'Jane Doe', 'email' => 'janedoe@example.com']); - static::assertEquals('update users set name = ?, email = ?', $query->toSql()); + static::assertEquals('UPDATE `users` SET `name` = ?, `email` = ?', $query->toSql()); static::assertEquals(['Jane Doe', 'janedoe@example.com'], $query->getBindings()); } @@ -56,7 +56,7 @@ public function delete(): void $query = new Query($this->createMock('PDO')); $query->delete('users'); - static::assertEquals('delete from users', $query->toSql()); + static::assertEquals('DELETE FROM `users`', $query->toSql()); static::assertEquals([], $query->getBindings()); } @@ -66,7 +66,7 @@ public function where(): void $query = new Query($this->createMock('PDO')); $query->where(['name' => 'Jane Doe', 'email' => 'janedoe@example.com']); - static::assertEquals('where name = ? and email = ?', $query->toSql()); + static::assertEquals('WHERE `name` = ? AND `email` = ?', $query->toSql()); static::assertEquals(['Jane Doe', 'janedoe@example.com'], $query->getBindings()); } @@ -76,7 +76,7 @@ public function whereIn(): void $query = new Query($this->createMock('PDO')); $query->whereIn('id', ['1', '2']); - static::assertEquals('where id in (?, ?)', $query->toSql()); + static::assertEquals('WHERE `id` IN (?, ?)', $query->toSql()); static::assertEquals(['1', '2'], $query->getBindings()); } @@ -86,7 +86,7 @@ public function whereNotIn(): void $query = new Query($this->createMock('PDO')); $query->whereNotIn('id', ['1', '2']); - static::assertEquals('where id not in (?, ?)', $query->toSql()); + static::assertEquals('WHERE `id` NOT IN (?, ?)', $query->toSql()); static::assertEquals(['1', '2'], $query->getBindings()); } @@ -96,7 +96,7 @@ public function compositeWhereIn(): void $query = new Query($this->createMock('PDO')); $query->whereIn(['id', 'company'], [['id' => '1', 'company' => '1'], ['id' => '2', 'company' => '1']]); - static::assertEquals('where (company, id) in ((?, ?), (?, ?))', $query->toSql()); + static::assertEquals('WHERE (`company`, `id`) IN ((?, ?), (?, ?))', $query->toSql()); static::assertEquals(['1', '1', '1', '2'], $query->getBindings()); } @@ -106,7 +106,7 @@ public function compositeWhereNotIn(): void $query = new Query($this->createMock('PDO')); $query->whereNotIn(['id', 'company'], [['id' => '1', 'company' => '1'], ['id' => '2', 'company' => '1']]); - static::assertEquals('where (company, id) not in ((?, ?), (?, ?))', $query->toSql()); + static::assertEquals('WHERE (`company`, `id`) NOT IN ((?, ?), (?, ?))', $query->toSql()); static::assertEquals(['1', '1', '1', '2'], $query->getBindings()); } diff --git a/tests/Unit/Extractors/AggregatorTest.php b/tests/Unit/Extractors/AggregatorTest.php index 1b01f632..f39d6385 100644 --- a/tests/Unit/Extractors/AggregatorTest.php +++ b/tests/Unit/Extractors/AggregatorTest.php @@ -165,6 +165,8 @@ public function discardIncompleteRowIndexMatching(array $iterators): void /** @test */ public function bigShuffledDataSet(): void { + $this->markTestSkipped('Tool long'); + $expected = 10 ** 4; $iterator = function (string $key, string $template) use ($expected): \Generator { diff --git a/tests/Unit/Extractors/DateDimensionTest.php b/tests/Unit/Extractors/DateDimensionTest.php index f6256a0e..2bcddb0c 100644 --- a/tests/Unit/Extractors/DateDimensionTest.php +++ b/tests/Unit/Extractors/DateDimensionTest.php @@ -332,7 +332,7 @@ private function iterateDimensions(DateDimension $extractor): array $currentDayTimestamp = (new \DateTimeImmutable($date[DateDimension::ROW_DATE_FULL]))->getTimestamp(); if (null !== $previousDayTimestamp) { - $delta = $currentDayTimestamp - $previousDayTimestamp - static::DAY_AS_SECONDS; + $delta = $currentDayTimestamp - $previousDayTimestamp - self::DAY_AS_SECONDS; } if ($delta > 0) { From 06868c1d6ae6d3526376c2d43b85a9d699292c69 Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 03:15:28 +0200 Subject: [PATCH 02/19] refacto: Query use WhereInterface --- Makefile | 2 +- phpstan.neon.dist | 4 - src/Database/Query.php | 149 ++++++------------ src/Database/WhereCompileResult.php | 21 +++ src/Database/WhereInCompositeStatement.php | 58 +++++++ src/Database/WhereInStatement.php | 41 +++++ src/Database/WhereStatement.php | 31 +++- ...reType.php => WhereStatementInterface.php} | 6 +- 8 files changed, 190 insertions(+), 122 deletions(-) create mode 100644 src/Database/WhereCompileResult.php create mode 100644 src/Database/WhereInCompositeStatement.php create mode 100644 src/Database/WhereInStatement.php rename src/Database/{WhereType.php => WhereStatementInterface.php} (65%) diff --git a/Makefile b/Makefile index f5ac45f5..1fdaca7e 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ phpcbf: phpstan: vendor/bin/phpstan clear-result-cache - vendor/bin/phpstan analyse + php -d memory_limit=2G vendor/bin/phpstan analyse phpcsfixer: vendor/bin/php-cs-fixer fix --dry-run --allow-risky=yes --diff diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f93bb0d6..f933db64 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,10 +7,6 @@ parameters: checkMissingIterableValueType: false checkGenericClassInNonGenericObjectType: false ignoreErrors: - - - message: '~^Variable method call on ~' - path: src/Database/Query.php - - message: '~^Variable method call on ~' path: src/Database/Statement.php diff --git a/src/Database/Query.php b/src/Database/Query.php index 090adfdd..c64a753b 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -13,6 +13,9 @@ class Query { + private const DEFAULT_MASK = '{column}'; + public const BACKTICKED_MASK = '`{column}`'; + /** * The database connection. */ @@ -30,8 +33,9 @@ class Query /** * The where constraints for the query. + * @var WhereStatementInterface[] */ - protected array $wheres = []; + protected array $whereStatements = []; /** * Create a new Query instance. @@ -74,6 +78,9 @@ public function getBindings(): array /** * Select statement. * + + /** + * @return $this */ public function select(string $table, ?array $columns = null): Query @@ -81,7 +88,7 @@ public function select(string $table, ?array $columns = null): Query $columns = \is_null($columns) ? '*' - : $this->implode($columns, '`{column}`'); + : self::implode($columns, self::BACKTICKED_MASK); $this->query[] = "SELECT $columns FROM `$table`"; @@ -97,9 +104,9 @@ public function insert(string $table, array $columns): Query { $this->bindings = array_merge($this->bindings, array_values($columns)); - $values = $this->implode($columns, '?'); + $values = self::implode($columns, '?'); - $columns = $this->implode(array_keys($columns), '`{column}`'); + $columns = self::implode(array_keys($columns), self::BACKTICKED_MASK); $this->query[] = "INSERT INTO `$table` ($columns) VALUES ($values)"; @@ -115,9 +122,9 @@ public function update(string $table, array $columns): Query { $this->bindings = array_merge($this->bindings, array_values($columns)); - $columns = $this->implode( + $columns = self::implode( array_keys($columns), - '`{column}` = ?' + sprintf("%s = ?", self::BACKTICKED_MASK), ); $this->query[] = "UPDATE `$table` SET $columns"; @@ -145,21 +152,19 @@ public function delete(string $table): Query public function where(array $columns): Query { foreach ($columns as $column => $value) { - $condition = [ - WhereStatement::TYPE => WhereType::Where, - WhereStatement::COLUMN => $column, - WhereStatement::BOOLEAN => WhereBoolean::And, - ]; - if (is_scalar($value)) { - $condition[WhereStatement::OPERATOR] = WhereOperator::Equal; - $condition[WhereStatement::VALUE] = $value; + $operator = WhereOperator::Equal; } else { - $condition[WhereStatement::OPERATOR] = WhereOperator::from($value[0]); - $condition[WhereStatement::VALUE] = $value[1]; + $operator = WhereOperator::from($value[0]); + $value = $value[1]; } - $this->wheres[] = $condition; + $this->whereStatements[] = new WhereStatement( + boolean: WhereBoolean::And, + operator: $operator, + column: $column, + value: $value, + ); } return $this; @@ -178,21 +183,19 @@ public function whereIn( WhereOperator $operator = WhereOperator::In ): Query { if (is_string($column)) { - $this->wheres[] = [ - WhereStatement::TYPE => WhereType::WhereIn, - WhereStatement::COLUMN => $column, - WhereStatement::MULTIPLE_VALUES => $values, - WhereStatement::OPERATOR => $operator, - WhereStatement::BOOLEAN => WhereBoolean::And, - ]; + $this->whereStatements[] = new WhereInStatement( + boolean: WhereBoolean::And, + operator: $operator, + column: $column, + multipleValues: $values, + ); } else { - $this->wheres[] = [ - WhereStatement::TYPE => WhereType::CompositeWhereIn, - WhereStatement::MULTIPLE_COLUMNS => $column, - WhereStatement::MULTIPLE_VALUES => $values, - WhereStatement::OPERATOR => $operator, - WhereStatement::BOOLEAN => WhereBoolean::And, - ]; + $this->whereStatements[] = new WhereInCompositeStatement( + boolean: WhereBoolean::And, + operator: $operator, + multipleColumns: $column, // :| + multipleValues: $values, + ); } return $this; @@ -215,94 +218,30 @@ public function whereNotIn($column, array $values): Query */ protected function compileWheres(): void { - if ([] === $this->wheres) { + if ([] === $this->whereStatements) { return; } $this->query[] = 'WHERE'; - foreach ($this->wheres as $index => $condition) { - $method = 'compile' . $condition[WhereStatement::TYPE]->value; - - if (0 == $index) { - $condition[WhereStatement::BOOLEAN] = WhereBoolean::Nothing; - } - - $this->query[] = trim($this->{$method}($condition)); - } - } - - /** - * Compile the basic where statement. - */ - protected function compileWhere(array $where): string - { - // All these if, empty, are here to clean the legacy code before the fork. See the git history. - $boolean = array_key_exists(WhereStatement::BOOLEAN, $where) ? $where[WhereStatement::BOOLEAN]->value : null; - $column = array_key_exists(WhereStatement::COLUMN, $where) ? $where[WhereStatement::COLUMN] : null; - $operator = array_key_exists(WhereStatement::OPERATOR, $where) ? $where[WhereStatement::OPERATOR]->value : null; - $value = array_key_exists(WhereStatement::VALUE, $where) ? $where[WhereStatement::VALUE] : null; - - $this->bindings[] = $value; - - return "$boolean `$column` $operator ?"; - } - - /** - * Compile the where in statement. - */ - protected function compileWhereIn(array $where): string - { - // All these if, empty, are here to clean the legacy code before the fork. See the git history. - $boolean = array_key_exists(WhereStatement::BOOLEAN, $where) ? $where[WhereStatement::BOOLEAN]->value : null; - $column = array_key_exists(WhereStatement::COLUMN, $where) ? $where[WhereStatement::COLUMN] : null; - $operator = array_key_exists(WhereStatement::OPERATOR, $where) ? $where[WhereStatement::OPERATOR]->value : null; - $multipleValues = array_key_exists(WhereStatement::MULTIPLE_VALUES, $where) ? $where[WhereStatement::MULTIPLE_VALUES] : null; - - $this->bindings = array_merge($this->bindings, $multipleValues); - - $parameters = $this->implode($multipleValues, '?'); - - return "$boolean `$column` $operator ($parameters)"; - } - - /** - * Compile the composite where in statecolumnment. - */ - protected function compileCompositeWhereIn(array $where): string - { - // All these if, empty, are here to clean the legacy code before the fork. See the git history. - $boolean = array_key_exists(WhereStatement::BOOLEAN, $where) ? $where[WhereStatement::BOOLEAN]->value : null; - $multipleColumns = array_key_exists(WhereStatement::MULTIPLE_COLUMNS, $where) ? $where[WhereStatement::MULTIPLE_COLUMNS] : null; - $operator = array_key_exists(WhereStatement::OPERATOR, $where) ? $where[WhereStatement::OPERATOR]->value : null; - $multipleValues = array_key_exists(WhereStatement::MULTIPLE_VALUES, $where) ? $where[WhereStatement::MULTIPLE_VALUES] : null; - - sort($multipleColumns); - - $parameters = []; - - foreach ($multipleValues as $value) { - ksort($value); + foreach ($this->whereStatements as $index => $statement) { + $result = $statement->compile($index); - $this->bindings = array_merge($this->bindings, array_values($value)); - - $parameters[] = "({$this->implode($value, '?')})"; + $this->query[] = $result->statement; + $this->bindings = \array_merge( + $this->bindings, + $result->bindings, + ); } - - $parameters = $this->implode($parameters); - - $multipleColumns = $this->implode($multipleColumns, '`{column}`'); - - return "$boolean ($multipleColumns) $operator ($parameters)"; } /** * Join array elements using a string mask. */ - protected function implode(array $columns, string $mask = '{column}'): string + public static function implode(array $columns, string $mask = self::DEFAULT_MASK): string { $columns = array_map(function ($column) use ($mask): string { - return str_replace('{column}', $column, $mask); + return str_replace(self::DEFAULT_MASK, $column, $mask); }, $columns); return implode(', ', $columns); diff --git a/src/Database/WhereCompileResult.php b/src/Database/WhereCompileResult.php new file mode 100644 index 00000000..12e2f69a --- /dev/null +++ b/src/Database/WhereCompileResult.php @@ -0,0 +1,21 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +class WhereCompileResult +{ + public function __construct( + public string $statement, + public array $bindings, + ) { + } +} diff --git a/src/Database/WhereInCompositeStatement.php b/src/Database/WhereInCompositeStatement.php new file mode 100644 index 00000000..eada4b9c --- /dev/null +++ b/src/Database/WhereInCompositeStatement.php @@ -0,0 +1,58 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +class WhereInCompositeStatement implements WhereStatementInterface +{ + public function __construct( + private WhereBoolean $boolean, + private WhereOperator $operator, + private array $multipleColumns, + private array $multipleValues, + ) { + } + + public function compile(int $index): WhereCompileResult + { + sort($this->multipleColumns); + + $parameters = []; + $bindings = []; + foreach ($this->multipleValues as $value) { + ksort($value); + + $bindings = array_merge($bindings, array_values($value)); + + $parameters[] = \sprintf( + "(%s)", + Query::implode($value, '?') + ); + } + + $parameters = Query::implode($parameters); + + $multipleColumns = Query::implode($this->multipleColumns, Query::BACKTICKED_MASK); + + return new WhereCompileResult( + \trim( + \sprintf( + '%s (%s) %s (%s)', + $index > 0 ? $this->boolean->value : '', + $multipleColumns, + $this->operator->value, + $parameters, + ) + ), + $bindings + ); + } +} diff --git a/src/Database/WhereInStatement.php b/src/Database/WhereInStatement.php new file mode 100644 index 00000000..69d4e4aa --- /dev/null +++ b/src/Database/WhereInStatement.php @@ -0,0 +1,41 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +class WhereInStatement implements WhereStatementInterface +{ + public function __construct( + private WhereBoolean $boolean, + private WhereOperator $operator, + private string $column, + private array $multipleValues, + ) { + } + + public function compile(int $index): WhereCompileResult + { + $parameters = Query::implode($this->multipleValues, '?'); + + return new WhereCompileResult( + \trim( + \sprintf( + '%s `%s` %s (%s)', + $index > 0 ? $this->boolean->value : '', + $this->column, + $this->operator->value, + $parameters, + ) + ), + $this->multipleValues, + ); + } +} diff --git a/src/Database/WhereStatement.php b/src/Database/WhereStatement.php index 06c26ff8..eecbde3a 100644 --- a/src/Database/WhereStatement.php +++ b/src/Database/WhereStatement.php @@ -11,13 +11,28 @@ namespace Wizaplace\Etl\Database; -class WhereStatement +class WhereStatement implements WhereStatementInterface { - const TYPE = 'type'; - const BOOLEAN = 'boolean'; - const MULTIPLE_COLUMNS = 'columns'; - const COLUMN = 'column'; - const OPERATOR = 'operator'; - const MULTIPLE_VALUES = 'values'; - const VALUE = 'value'; + public function __construct( + private WhereBoolean $boolean, + private WhereOperator $operator, + private string $column, + private mixed $value, + ) { + } + + public function compile(int $index): WhereCompileResult + { + return new WhereCompileResult( + \trim( + \sprintf( + '%s `%s` %s ?', + $index > 0 ? $this->boolean->value : '', + $this->column, + $this->operator->value, + ) + ), + [$this->value], + ); + } } diff --git a/src/Database/WhereType.php b/src/Database/WhereStatementInterface.php similarity index 65% rename from src/Database/WhereType.php rename to src/Database/WhereStatementInterface.php index ca8474bf..edb6a83f 100644 --- a/src/Database/WhereType.php +++ b/src/Database/WhereStatementInterface.php @@ -11,9 +11,7 @@ namespace Wizaplace\Etl\Database; -enum WhereType: string +interface WhereStatementInterface { - case Where = 'Where'; - case WhereIn = 'WhereIn'; - case CompositeWhereIn = 'CompositeWhereIn'; + public function compile(int $index): WhereCompileResult; } From d4b3fe9f6dcf820f822be85202bf7caf25b64cb2 Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 05:21:40 +0200 Subject: [PATCH 03/19] refacto: Statement use WhereInterface --- src/Database/Query.php | 20 ++--- src/Database/Statement.php | 76 +++++++------------ src/Database/WhereCompileResult.php | 2 +- ...tatement.php => WhereInCompositeQuery.php} | 2 +- ...{WhereInStatement.php => WhereInQuery.php} | 2 +- ...tementInterface.php => WhereInterface.php} | 2 +- src/Database/WhereQuery.php | 38 ++++++++++ src/Database/WhereStatement.php | 8 +- tests/Unit/Database/StatementTest.php | 14 ++-- tests/Unit/Extractors/AggregatorTest.php | 2 - 10 files changed, 92 insertions(+), 74 deletions(-) rename src/Database/{WhereInCompositeStatement.php => WhereInCompositeQuery.php} (95%) rename src/Database/{WhereInStatement.php => WhereInQuery.php} (94%) rename src/Database/{WhereStatementInterface.php => WhereInterface.php} (89%) create mode 100644 src/Database/WhereQuery.php diff --git a/src/Database/Query.php b/src/Database/Query.php index c64a753b..1c86dfbf 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -13,7 +13,7 @@ class Query { - private const DEFAULT_MASK = '{column}'; + public const DEFAULT_MASK = '{column}'; public const BACKTICKED_MASK = '`{column}`'; /** @@ -33,9 +33,9 @@ class Query /** * The where constraints for the query. - * @var WhereStatementInterface[] + * @var WhereInterface[] */ - protected array $whereStatements = []; + protected array $whereQueries = []; /** * Create a new Query instance. @@ -159,7 +159,7 @@ public function where(array $columns): Query $value = $value[1]; } - $this->whereStatements[] = new WhereStatement( + $this->whereQueries[] = new WhereQuery( boolean: WhereBoolean::And, operator: $operator, column: $column, @@ -183,14 +183,14 @@ public function whereIn( WhereOperator $operator = WhereOperator::In ): Query { if (is_string($column)) { - $this->whereStatements[] = new WhereInStatement( + $this->whereQueries[] = new WhereInQuery( boolean: WhereBoolean::And, operator: $operator, column: $column, multipleValues: $values, ); } else { - $this->whereStatements[] = new WhereInCompositeStatement( + $this->whereQueries[] = new WhereInCompositeQuery( boolean: WhereBoolean::And, operator: $operator, multipleColumns: $column, // :| @@ -218,16 +218,16 @@ public function whereNotIn($column, array $values): Query */ protected function compileWheres(): void { - if ([] === $this->whereStatements) { + if ([] === $this->whereQueries) { return; } $this->query[] = 'WHERE'; - foreach ($this->whereStatements as $index => $statement) { - $result = $statement->compile($index); + foreach ($this->whereQueries as $index => $whereQuery) { + $result = $whereQuery->compile($index); - $this->query[] = $result->statement; + $this->query[] = $result->output; $this->bindings = \array_merge( $this->bindings, $result->bindings, diff --git a/src/Database/Statement.php b/src/Database/Statement.php index ddd5983d..970a21a8 100644 --- a/src/Database/Statement.php +++ b/src/Database/Statement.php @@ -26,7 +26,7 @@ class Statement /** * The where constraints for the query. */ - protected array $wheres = []; + protected array $whereStatements = []; /** * Create a new Statement instance. @@ -68,11 +68,13 @@ public function toSql(): string * * @return $this */ - public function select(string $table, array $columns = ['*']): Statement + public function select(string $table, ?array $columns = null): Statement { - $columns = $this->implode($columns); + $columns = \is_null($columns) + ? '*' + : Query::implode($columns, Query::BACKTICKED_MASK); - $this->query[] = "select $columns from $table"; + $this->query[] = "SELECT $columns FROM `$table`"; return $this; } @@ -84,11 +86,11 @@ public function select(string $table, array $columns = ['*']): Statement */ public function insert(string $table, array $columns): Statement { - $values = $this->implode($columns, ':{column}'); + $values = Query::implode($columns, ':{column}'); - $columns = $this->implode($columns); + $columns = Query::implode($columns, Query::BACKTICKED_MASK); - $this->query[] = "insert into $table ($columns) values ($values)"; + $this->query[] = "INSERT INTO `$table` ($columns) values ($values)"; return $this; } @@ -100,9 +102,16 @@ public function insert(string $table, array $columns): Statement */ public function update(string $table, array $columns): Statement { - $columns = $this->implode($columns, '{column} = :{column}'); + $columns = Query::implode( + $columns, + \sprintf( + '%s = :%s', + Query::BACKTICKED_MASK, + Query::DEFAULT_MASK, + ) + ); - $this->query[] = "update $table set $columns"; + $this->query[] = "UPDATE `$table` SET $columns"; return $this; } @@ -114,7 +123,7 @@ public function update(string $table, array $columns): Statement */ public function delete(string $table): Statement { - $this->query[] = "delete from $table"; + $this->query[] = "DELETE FROM `$table`"; return $this; } @@ -127,9 +136,11 @@ public function delete(string $table): Statement public function where(array $columns): Statement { foreach ($columns as $column) { - $this->wheres[] = [ - 'type' => 'Where', 'column' => $column, 'operator' => '=', 'boolean' => 'and', - ]; + $this->whereStatements[] = new WhereStatement( + boolean: WhereBoolean::And, + operator: WhereOperator::Equal, + column: $column, + ); } return $this; @@ -140,45 +151,16 @@ public function where(array $columns): Statement */ protected function compileWheres(): void { - if ([] === $this->wheres) { + if ([] === $this->whereStatements) { return; } - $this->query[] = 'where'; + $this->query[] = 'WHERE'; - foreach ($this->wheres as $index => $condition) { - $method = 'compile' . $condition['type']; + foreach ($this->whereStatements as $index => $whereQuery) { + $result = $whereQuery->compile($index); - if (0 == $index) { - $condition['boolean'] = ''; - } - - $this->query[] = trim($this->{$method}($condition)); + $this->query[] = $result->output; } } - - /** - * Compile the basic where statement. - */ - protected function compileWhere(array $where): string - { - // This code is here to remove the use of the extract() method in the original repo. See the git history. - $boolean = array_key_exists('boolean', $where) ? $where['boolean'] : null; - $column = array_key_exists('column', $where) ? $where['column'] : null; - $operator = array_key_exists('operator', $where) ? $where['operator'] : null; - - return "$boolean $column $operator :$column"; - } - - /** - * Join array elements using a string mask. - */ - protected function implode(array $columns, string $mask = '{column}'): string - { - $columns = array_map(function ($column) use ($mask): string { - return str_replace('{column}', $column, $mask); - }, $columns); - - return implode(', ', $columns); - } } diff --git a/src/Database/WhereCompileResult.php b/src/Database/WhereCompileResult.php index 12e2f69a..25565de2 100644 --- a/src/Database/WhereCompileResult.php +++ b/src/Database/WhereCompileResult.php @@ -14,7 +14,7 @@ class WhereCompileResult { public function __construct( - public string $statement, + public string $output, public array $bindings, ) { } diff --git a/src/Database/WhereInCompositeStatement.php b/src/Database/WhereInCompositeQuery.php similarity index 95% rename from src/Database/WhereInCompositeStatement.php rename to src/Database/WhereInCompositeQuery.php index eada4b9c..57bb6bde 100644 --- a/src/Database/WhereInCompositeStatement.php +++ b/src/Database/WhereInCompositeQuery.php @@ -11,7 +11,7 @@ namespace Wizaplace\Etl\Database; -class WhereInCompositeStatement implements WhereStatementInterface +class WhereInCompositeQuery implements WhereInterface { public function __construct( private WhereBoolean $boolean, diff --git a/src/Database/WhereInStatement.php b/src/Database/WhereInQuery.php similarity index 94% rename from src/Database/WhereInStatement.php rename to src/Database/WhereInQuery.php index 69d4e4aa..8fd1c52b 100644 --- a/src/Database/WhereInStatement.php +++ b/src/Database/WhereInQuery.php @@ -11,7 +11,7 @@ namespace Wizaplace\Etl\Database; -class WhereInStatement implements WhereStatementInterface +class WhereInQuery implements WhereInterface { public function __construct( private WhereBoolean $boolean, diff --git a/src/Database/WhereStatementInterface.php b/src/Database/WhereInterface.php similarity index 89% rename from src/Database/WhereStatementInterface.php rename to src/Database/WhereInterface.php index edb6a83f..e5c0e17d 100644 --- a/src/Database/WhereStatementInterface.php +++ b/src/Database/WhereInterface.php @@ -11,7 +11,7 @@ namespace Wizaplace\Etl\Database; -interface WhereStatementInterface +interface WhereInterface { public function compile(int $index): WhereCompileResult; } diff --git a/src/Database/WhereQuery.php b/src/Database/WhereQuery.php new file mode 100644 index 00000000..44d65ff8 --- /dev/null +++ b/src/Database/WhereQuery.php @@ -0,0 +1,38 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +class WhereQuery implements WhereInterface +{ + public function __construct( + private WhereBoolean $boolean, + private WhereOperator $operator, + private string $column, + private mixed $value, + ) { + } + + public function compile(int $index): WhereCompileResult + { + return new WhereCompileResult( + \trim( + \sprintf( + '%s `%s` %s ?', + $index > 0 ? $this->boolean->value : '', + $this->column, + $this->operator->value, + ) + ), + [$this->value], + ); + } +} diff --git a/src/Database/WhereStatement.php b/src/Database/WhereStatement.php index eecbde3a..5d9270ae 100644 --- a/src/Database/WhereStatement.php +++ b/src/Database/WhereStatement.php @@ -11,13 +11,12 @@ namespace Wizaplace\Etl\Database; -class WhereStatement implements WhereStatementInterface +class WhereStatement implements WhereInterface { public function __construct( private WhereBoolean $boolean, private WhereOperator $operator, private string $column, - private mixed $value, ) { } @@ -26,13 +25,14 @@ public function compile(int $index): WhereCompileResult return new WhereCompileResult( \trim( \sprintf( - '%s `%s` %s ?', + '%s `%s` %s :%s', $index > 0 ? $this->boolean->value : '', $this->column, $this->operator->value, + $this->column, ) ), - [$this->value], + [], ); } } diff --git a/tests/Unit/Database/StatementTest.php b/tests/Unit/Database/StatementTest.php index c8b8018c..6204f24d 100644 --- a/tests/Unit/Database/StatementTest.php +++ b/tests/Unit/Database/StatementTest.php @@ -24,12 +24,12 @@ public function select(): void $statement = new Statement($this->createMock('PDO')); $statement->select('users'); - static::assertEquals('select * from users', $statement->toSql()); + static::assertEquals('SELECT * FROM `users`', $statement->toSql()); $statement = new Statement($this->createMock('PDO')); $statement->select('users', ['name', 'email']); - static::assertEquals('select name, email from users', $statement->toSql()); + static::assertEquals('SELECT `name`, `email` FROM `users`', $statement->toSql()); } /** @test */ @@ -38,7 +38,7 @@ public function insert(): void $statement = new Statement($this->createMock('PDO')); $statement->insert('users', ['name', 'email']); - static::assertEquals('insert into users (name, email) values (:name, :email)', $statement->toSql()); + static::assertEquals('INSERT INTO `users` (`name`, `email`) values (:name, :email)', $statement->toSql()); } /** @test */ @@ -47,7 +47,7 @@ public function update(): void $statement = new Statement($this->createMock('PDO')); $statement->update('users', ['name', 'email']); - static::assertEquals('update users set name = :name, email = :email', $statement->toSql()); + static::assertEquals('UPDATE `users` SET `name` = :name, `email` = :email', $statement->toSql()); } /** @test */ @@ -56,7 +56,7 @@ public function delete(): void $statement = new Statement($this->createMock('PDO')); $statement->delete('users'); - static::assertEquals('delete from users', $statement->toSql()); + static::assertEquals('DELETE FROM `users`', $statement->toSql()); } /** @test */ @@ -65,7 +65,7 @@ public function where(): void $statement = new Statement($this->createMock('PDO')); $statement->where(['name', 'email']); - static::assertEquals('where name = :name and email = :email', $statement->toSql()); + static::assertEquals('WHERE `name` = :name AND `email` = :email', $statement->toSql()); } /** @test */ @@ -102,7 +102,7 @@ public function prepareInvalid(): void $statement->prepare(); static::fail('An exception should have been thrown'); } catch (\PDOException $exception) { - static::assertEquals('SQLSTATE[HY000]: General error: 1 near ">": syntax error', $exception->getMessage()); + static::assertEquals('SQLSTATE[HY000]: General error: 1 no such table: foo', $exception->getMessage()); } catch (\Exception $exception) { static::fail('An instance of ' . \PDOException::class . ' should have been thrown'); } diff --git a/tests/Unit/Extractors/AggregatorTest.php b/tests/Unit/Extractors/AggregatorTest.php index f39d6385..1b01f632 100644 --- a/tests/Unit/Extractors/AggregatorTest.php +++ b/tests/Unit/Extractors/AggregatorTest.php @@ -165,8 +165,6 @@ public function discardIncompleteRowIndexMatching(array $iterators): void /** @test */ public function bigShuffledDataSet(): void { - $this->markTestSkipped('Tool long'); - $expected = 10 ** 4; $iterator = function (string $key, string $template) use ($expected): \Generator { From e272d76c501eb14f825abeb1f5f35c9f17ca889a Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 05:38:07 +0200 Subject: [PATCH 04/19] chore: Helpers class --- src/Database/Helpers.php | 30 ++++++++++++++++++++++++++ src/Database/Query.php | 25 +++++---------------- src/Database/Statement.php | 12 +++++------ src/Database/WhereInCompositeQuery.php | 6 +++--- src/Database/WhereInQuery.php | 2 +- 5 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 src/Database/Helpers.php diff --git a/src/Database/Helpers.php b/src/Database/Helpers.php new file mode 100644 index 00000000..eed5a0e2 --- /dev/null +++ b/src/Database/Helpers.php @@ -0,0 +1,30 @@ + + * @copyright Copyright (c) Wizacha + * @copyright Copyright (c) Leonardo Marquine + * @license MIT + */ + +declare(strict_types=1); + +namespace Wizaplace\Etl\Database; + +class Helpers +{ + public const DEFAULT_MASK = '{column}'; + public const BACKTICKED_MASK = '`{column}`'; + + /** + * Join array elements using a string mask. + */ + public static function implode(array $columns, string $mask = self::DEFAULT_MASK): string + { + $columns = array_map(function ($column) use ($mask): string { + return str_replace(self::DEFAULT_MASK, $column, $mask); + }, $columns); + + return implode(', ', $columns); + } +} diff --git a/src/Database/Query.php b/src/Database/Query.php index 1c86dfbf..bb935f42 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -13,9 +13,6 @@ class Query { - public const DEFAULT_MASK = '{column}'; - public const BACKTICKED_MASK = '`{column}`'; - /** * The database connection. */ @@ -88,7 +85,7 @@ public function select(string $table, ?array $columns = null): Query $columns = \is_null($columns) ? '*' - : self::implode($columns, self::BACKTICKED_MASK); + : Helpers::implode($columns, Helpers::BACKTICKED_MASK); $this->query[] = "SELECT $columns FROM `$table`"; @@ -104,9 +101,9 @@ public function insert(string $table, array $columns): Query { $this->bindings = array_merge($this->bindings, array_values($columns)); - $values = self::implode($columns, '?'); + $values = Helpers::implode($columns, '?'); - $columns = self::implode(array_keys($columns), self::BACKTICKED_MASK); + $columns = Helpers::implode(array_keys($columns), Helpers::BACKTICKED_MASK); $this->query[] = "INSERT INTO `$table` ($columns) VALUES ($values)"; @@ -122,9 +119,9 @@ public function update(string $table, array $columns): Query { $this->bindings = array_merge($this->bindings, array_values($columns)); - $columns = self::implode( + $columns = Helpers::implode( array_keys($columns), - sprintf("%s = ?", self::BACKTICKED_MASK), + sprintf("%s = ?", Helpers::BACKTICKED_MASK), ); $this->query[] = "UPDATE `$table` SET $columns"; @@ -234,16 +231,4 @@ protected function compileWheres(): void ); } } - - /** - * Join array elements using a string mask. - */ - public static function implode(array $columns, string $mask = self::DEFAULT_MASK): string - { - $columns = array_map(function ($column) use ($mask): string { - return str_replace(self::DEFAULT_MASK, $column, $mask); - }, $columns); - - return implode(', ', $columns); - } } diff --git a/src/Database/Statement.php b/src/Database/Statement.php index 970a21a8..30702266 100644 --- a/src/Database/Statement.php +++ b/src/Database/Statement.php @@ -72,7 +72,7 @@ public function select(string $table, ?array $columns = null): Statement { $columns = \is_null($columns) ? '*' - : Query::implode($columns, Query::BACKTICKED_MASK); + : Helpers::implode($columns, Helpers::BACKTICKED_MASK); $this->query[] = "SELECT $columns FROM `$table`"; @@ -86,9 +86,9 @@ public function select(string $table, ?array $columns = null): Statement */ public function insert(string $table, array $columns): Statement { - $values = Query::implode($columns, ':{column}'); + $values = Helpers::implode($columns, ':{column}'); - $columns = Query::implode($columns, Query::BACKTICKED_MASK); + $columns = Helpers::implode($columns, Helpers::BACKTICKED_MASK); $this->query[] = "INSERT INTO `$table` ($columns) values ($values)"; @@ -102,12 +102,12 @@ public function insert(string $table, array $columns): Statement */ public function update(string $table, array $columns): Statement { - $columns = Query::implode( + $columns = Helpers::implode( $columns, \sprintf( '%s = :%s', - Query::BACKTICKED_MASK, - Query::DEFAULT_MASK, + Helpers::BACKTICKED_MASK, + Helpers::DEFAULT_MASK, ) ); diff --git a/src/Database/WhereInCompositeQuery.php b/src/Database/WhereInCompositeQuery.php index 57bb6bde..080f9e38 100644 --- a/src/Database/WhereInCompositeQuery.php +++ b/src/Database/WhereInCompositeQuery.php @@ -34,13 +34,13 @@ public function compile(int $index): WhereCompileResult $parameters[] = \sprintf( "(%s)", - Query::implode($value, '?') + Helpers::implode($value, '?') ); } - $parameters = Query::implode($parameters); + $parameters = Helpers::implode($parameters); - $multipleColumns = Query::implode($this->multipleColumns, Query::BACKTICKED_MASK); + $multipleColumns = Helpers::implode($this->multipleColumns, Helpers::BACKTICKED_MASK); return new WhereCompileResult( \trim( diff --git a/src/Database/WhereInQuery.php b/src/Database/WhereInQuery.php index 8fd1c52b..0aadc3bd 100644 --- a/src/Database/WhereInQuery.php +++ b/src/Database/WhereInQuery.php @@ -23,7 +23,7 @@ public function __construct( public function compile(int $index): WhereCompileResult { - $parameters = Query::implode($this->multipleValues, '?'); + $parameters = Helpers::implode($this->multipleValues, '?'); return new WhereCompileResult( \trim( From c6d6c18e855b278667881a3481753e32927fd693 Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 05:46:09 +0200 Subject: [PATCH 05/19] dev: coverage Makefile command --- Makefile | 8 + cov.xml | 1444 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1452 insertions(+) create mode 100644 cov.xml diff --git a/Makefile b/Makefile index 1fdaca7e..03b44b1b 100644 --- a/Makefile +++ b/Makefile @@ -16,3 +16,11 @@ test: infection: vendor/bin/infection + +PHPUNIT_REPORT_PATH = /tmp/phpunit_coverage_report +coverage: + XDEBUG_MODE=coverage vendor/bin/phpunit \ + --coverage-clover cov.xml \ + --coverage-filter src \ + --coverage-html $(PHPUNIT_REPORT_PATH) + xdg-open $(PHPUNIT_REPORT_PATH)/index.html diff --git a/cov.xml b/cov.xml new file mode 100644 index 00000000..02c34537 --- /dev/null +++ b/cov.xml @@ -0,0 +1,1444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7f2326d67194b45b1cdde1d0adccc2b0e0c5deb7 Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 05:50:45 +0200 Subject: [PATCH 06/19] fix: remove cov.xml + update gitignore --- .gitignore | 1 + cov.xml | 1444 ---------------------------------------------------- 2 files changed, 1 insertion(+), 1444 deletions(-) delete mode 100644 cov.xml diff --git a/.gitignore b/.gitignore index e6d98de3..c873af91 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ var/ phpcs.xml phpstan.neon phpunit.xml +cov.xml \ No newline at end of file diff --git a/cov.xml b/cov.xml deleted file mode 100644 index 02c34537..00000000 --- a/cov.xml +++ /dev/null @@ -1,1444 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 1d6765752ccba4c1eea06c2a22c325dcbda85d6a Mon Sep 17 00:00:00 2001 From: Merleur l'enchantin Date: Thu, 7 Sep 2023 06:11:13 +0200 Subject: [PATCH 07/19] fix: remove ignoreErrors for Statement --- phpstan.neon.dist | 4 ---- 1 file changed, 4 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f933db64..20385a80 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,10 +7,6 @@ parameters: checkMissingIterableValueType: false checkGenericClassInNonGenericObjectType: false ignoreErrors: - - - message: '~^Variable method call on ~' - path: src/Database/Statement.php - - message: '~^Variable method call on ~' path: src/Etl.php From 7593273f56c74e96d7842bba4d13baf2ca32e677 Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 10:16:49 +0200 Subject: [PATCH 08/19] fix: phpcsfixer --- src/Database/Query.php | 9 +++------ src/Database/Statement.php | 2 +- src/Database/WhereInCompositeQuery.php | 2 +- src/Etl.php | 3 +-- src/Extractors/DateDimension.php | 4 ++-- src/Extractors/Extractor.php | 7 ++----- src/Loaders/InsertUpdate.php | 6 ++---- src/Loaders/Loader.php | 4 ---- src/Row.php | 19 ------------------- src/Transformers/UniqueRows.php | 6 ------ 10 files changed, 12 insertions(+), 50 deletions(-) diff --git a/src/Database/Query.php b/src/Database/Query.php index bb935f42..2a892d7a 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -30,6 +30,7 @@ class Query /** * The where constraints for the query. + * * @var WhereInterface[] */ protected array $whereQueries = []; @@ -75,14 +76,10 @@ public function getBindings(): array /** * Select statement. * - - /** - * @return $this */ - public function select(string $table, ?array $columns = null): Query + public function select(string $table, array $columns = null): Query { - $columns = \is_null($columns) ? '*' : Helpers::implode($columns, Helpers::BACKTICKED_MASK); @@ -121,7 +118,7 @@ public function update(string $table, array $columns): Query $columns = Helpers::implode( array_keys($columns), - sprintf("%s = ?", Helpers::BACKTICKED_MASK), + sprintf('%s = ?', Helpers::BACKTICKED_MASK), ); $this->query[] = "UPDATE `$table` SET $columns"; diff --git a/src/Database/Statement.php b/src/Database/Statement.php index 30702266..b52b38b9 100644 --- a/src/Database/Statement.php +++ b/src/Database/Statement.php @@ -68,7 +68,7 @@ public function toSql(): string * * @return $this */ - public function select(string $table, ?array $columns = null): Statement + public function select(string $table, array $columns = null): Statement { $columns = \is_null($columns) ? '*' diff --git a/src/Database/WhereInCompositeQuery.php b/src/Database/WhereInCompositeQuery.php index 080f9e38..0f613454 100644 --- a/src/Database/WhereInCompositeQuery.php +++ b/src/Database/WhereInCompositeQuery.php @@ -33,7 +33,7 @@ public function compile(int $index): WhereCompileResult $bindings = array_merge($bindings, array_values($value)); $parameters[] = \sprintf( - "(%s)", + '(%s)', Helpers::implode($value, '?') ); } diff --git a/src/Etl.php b/src/Etl.php index 9ebabfab..fde22144 100644 --- a/src/Etl.php +++ b/src/Etl.php @@ -28,7 +28,7 @@ class Etl /** * Create a new Etl instance. */ - public function __construct(?Pipeline $pipeline = null) + public function __construct(Pipeline $pipeline = null) { $this->pipeline = $pipeline ?? new Pipeline(); } @@ -40,7 +40,6 @@ public function __construct(?Pipeline $pipeline = null) * Etl\Extractor\Csv needs a string * Etl\Extractor\Collection an \Iterator * - * @param mixed $input * @param array $options * * @return $this diff --git a/src/Extractors/DateDimension.php b/src/Extractors/DateDimension.php index 4e227f61..6a91c3e9 100644 --- a/src/Extractors/DateDimension.php +++ b/src/Extractors/DateDimension.php @@ -75,12 +75,12 @@ public function __construct() $this->startDate ??= $this->getCenterDateTime() ->sub($defaultBoundInterval) - ->format(static::CENTER_DATE_FORMAT); + ->format(self::CENTER_DATE_FORMAT); $this->endDate ??= $this->getCenterDateTime() ->add($defaultBoundInterval) ->sub($dayInterval) - ->format(static::CENTER_DATE_FORMAT); + ->format(self::CENTER_DATE_FORMAT); } /** diff --git a/src/Extractors/Extractor.php b/src/Extractors/Extractor.php index 3934b226..e26a3cc0 100644 --- a/src/Extractors/Extractor.php +++ b/src/Extractors/Extractor.php @@ -15,17 +15,14 @@ abstract class Extractor extends Step { - /** @var mixed */ - protected $input; + protected mixed $input; /** * Set the extractor input. * - * @param mixed $input - * * @return $this */ - public function input($input): Extractor + public function input(mixed $input): Extractor { $this->input = $input; diff --git a/src/Loaders/InsertUpdate.php b/src/Loaders/InsertUpdate.php index 68c79736..b248fcdf 100644 --- a/src/Loaders/InsertUpdate.php +++ b/src/Loaders/InsertUpdate.php @@ -23,8 +23,6 @@ class InsertUpdate extends Insert /** * The primary key. - * - * @var mixed */ protected $key = ['id']; @@ -38,14 +36,14 @@ class InsertUpdate extends Insert * * @var \PDOStatement|false|null */ - protected $select = null; + protected $select; /** * The update statement. * * @var \PDOStatement|false|null */ - protected $update = null; + protected $update; /** * Properties that can be set via the options method. diff --git a/src/Loaders/Loader.php b/src/Loaders/Loader.php index 8bea81e2..cc018b26 100644 --- a/src/Loaders/Loader.php +++ b/src/Loaders/Loader.php @@ -18,16 +18,12 @@ abstract class Loader extends Step { /** * The loader output. - * - * @var mixed */ protected $output; /** * Set the loader output. * - * @param mixed $output - * * @return $this */ public function output($output): Loader diff --git a/src/Row.php b/src/Row.php index 89d4e7bf..1f8a8d12 100644 --- a/src/Row.php +++ b/src/Row.php @@ -38,8 +38,6 @@ public function __construct(array $attributes) /** * Set a row attribute. - * - * @param mixed $value */ public function set(string $key, $value): self { @@ -50,8 +48,6 @@ public function set(string $key, $value): self /** * Get a row attribute. - * - * @return mixed */ public function get(string $key) { @@ -68,8 +64,6 @@ public function remove(string $key): void /** * Get a row attribute, and remove it. - * - * @return mixed */ public function pull(string $key) { @@ -142,8 +136,6 @@ public function isIncomplete(): bool /** * Dynamically retrieve attributes on the row. - * - * @return mixed */ public function __get(string $key) { @@ -152,8 +144,6 @@ public function __get(string $key) /** * Dynamically set attributes on the row. - * - * @param mixed $value */ public function __set(string $key, $value): void { @@ -162,8 +152,6 @@ public function __set(string $key, $value): void /** * Determine if the given attribute exists. - * - * @param mixed $offset */ public function offsetExists($offset): bool { @@ -172,8 +160,6 @@ public function offsetExists($offset): bool /** * Get the value for a given offset. - * - * @param mixed $offset */ public function offsetGet($offset): mixed { @@ -182,9 +168,6 @@ public function offsetGet($offset): mixed /** * Set the value for a given offset. - * - * @param mixed $offset - * @param mixed $value */ public function offsetSet($offset, $value): void { @@ -193,8 +176,6 @@ public function offsetSet($offset, $value): void /** * Unset the value for a given offset. - * - * @param mixed $offset */ public function offsetUnset($offset): void { diff --git a/src/Transformers/UniqueRows.php b/src/Transformers/UniqueRows.php index c70cac1e..76747ab6 100644 --- a/src/Transformers/UniqueRows.php +++ b/src/Transformers/UniqueRows.php @@ -69,8 +69,6 @@ public function transform(Row $row): void /** * Prepare the given row for comparison. - * - * @return mixed */ protected function prepare(Row $row) { @@ -85,8 +83,6 @@ protected function prepare(Row $row) /** * Verify if the subject is duplicate. - * - * @param mixed $subject */ protected function isDuplicate($subject): bool { @@ -95,8 +91,6 @@ protected function isDuplicate($subject): bool /** * Register the subject for future comparison. - * - * @param mixed $subject */ protected function register($subject): void { From e036c1a0502881a63b985d64382b2b3a870349d9 Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 10:18:59 +0200 Subject: [PATCH 09/19] dev: nix shell env --- Makefile | 3 +++ composer.json | 25 +++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 03b44b1b..29d8608d 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +dev: + nix shell github:loophp/nix-shell --impure + phpcs: vendor/bin/phpcs -n diff --git a/composer.json b/composer.json index 52cc4a91..c75fe559 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,16 @@ { "name": "wizaplace/php-etl", "description": "Extract, Transform and Load data using this PHP written migration library.", - "keywords": ["etl", "extract", "transform", "load", "extraction", "transformation", "data", "symfony"], + "keywords": [ + "etl", + "extract", + "transform", + "load", + "extraction", + "transformation", + "data", + "symfony" + ], "license": "MIT", "authors": [ { @@ -22,7 +31,7 @@ }, "require": { "php": "~8.1", - "softcreatr/jsonpath": "^0.7.2" + "softcreatr/jsonpath": "^0.8.3" }, "autoload": { "psr-4": { @@ -34,12 +43,13 @@ "ext-json": "*", "ext-pdo_sqlite": "*", "ext-xmlreader": "*", + "ext-xdebug": "*", "friendsofphp/php-cs-fixer": "^3.4", "infection/infection": ">=0.15", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.100", - "phpstan/phpstan-deprecation-rules": "^0.12.6", - "phpstan/phpstan-strict-rules": "^0.12.11", + "phpstan/phpstan": "1.3.1", + "phpstan/phpstan-deprecation-rules": "^1.1.4", + "phpstan/phpstan-strict-rules": "^1.5.1", "phpunit/phpunit": ">=8", "squizlabs/php_codesniffer": "^3.5" }, @@ -64,7 +74,10 @@ "phpstan --memory-limit=256M analyze" ], "test": "phpunit", - "check": ["@scan", "@test"] + "check": [ + "@scan", + "@test" + ] }, "minimum-stability": "dev", "prefer-stable": true From dc63bb0c15e5de72a9f8e2884be0ead8973cfc70 Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 10:19:28 +0200 Subject: [PATCH 10/19] fix: infection --- .gitignore | 2 +- Makefile | 4 ++-- infection.json.dist | 2 +- phpunit.xml.dist | 39 ++++++++++++++++++++------------------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index c873af91..de392a34 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ composer.lock .phpunit.cache .idea var/ +cov.xml # For these quality tools, the *.dist form should be in VCS and the forms # below should be reserved for local customizations. @@ -14,4 +15,3 @@ var/ phpcs.xml phpstan.neon phpunit.xml -cov.xml \ No newline at end of file diff --git a/Makefile b/Makefile index 29d8608d..76ca9a4a 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ dev: nix shell github:loophp/nix-shell --impure phpcs: - vendor/bin/phpcs -n + vendor/bin/phpcs -n --parallel=8 phpcbf: vendor/bin/phpcbf @@ -18,7 +18,7 @@ test: vendor/bin/phpunit --testdox infection: - vendor/bin/infection + XDEBUG_MODE=coverage vendor/bin/infection -j8 PHPUNIT_REPORT_PATH = /tmp/phpunit_coverage_report coverage: diff --git a/infection.json.dist b/infection.json.dist index c0435ca2..e6d29eca 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -21,5 +21,5 @@ } }, "testFramework":"phpunit", - "testFrameworkOptions": "-vvv" + } \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 73998fd8..1f04772d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,29 @@ - - - src - - + ./tests/Unit + + + src + + From be09f4091b07c1e4ff01bfc7b5c515a743008fce Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 10:23:50 +0200 Subject: [PATCH 11/19] ci: composer ignore ext-xdebug --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 84ff0344..dc8d7242 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -26,7 +26,7 @@ jobs: if [[ ! -f vendor/autoload.php ]]; then curl https://getcomposer.org/composer-stable.phar --location --silent --output /usr/bin/composer; \ chmod +x /usr/bin/composer; \ - composer install --no-progress --no-interaction; \ + composer install --no-progress --no-interaction --ignore-platform-req=ext-xdebug; \ fi - save_cache: key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }} From 1b6a3d0d41901cc2c5a98174e99cc683da343e92 Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 10:27:15 +0200 Subject: [PATCH 12/19] fix: phpstan dependencies --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c75fe559..e2e595c5 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "friendsofphp/php-cs-fixer": "^3.4", "infection/infection": ">=0.15", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "1.3.1", + "phpstan/phpstan": "^1.11", "phpstan/phpstan-deprecation-rules": "^1.1.4", "phpstan/phpstan-strict-rules": "^1.5.1", "phpunit/phpunit": ">=8", From e8b8c3d4da01f839f8ef553577035fc5d01ee401 Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 10:30:40 +0200 Subject: [PATCH 13/19] ci: composer (8.2 as well) ignore ext-xdebug --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dc8d7242..ff7e4471 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -93,7 +93,7 @@ jobs: if [[ ! -f vendor/autoload.php ]]; then curl https://getcomposer.org/composer-stable.phar --location --silent --output /usr/bin/composer; \ chmod +x /usr/bin/composer; \ - composer install --no-progress --no-interaction; \ + composer install --no-progress --no-interaction --ignore-platform-req=ext-xdebug; \ fi - save_cache: key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }} From 9fc4faabeceb0636a56a3194a9f641b03f55ae8a Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 12:07:10 +0200 Subject: [PATCH 14/19] fix: phpstan --- phpstan.neon.dist | 5 -- src/Etl.php | 2 +- src/Loaders/InsertUpdate.php | 4 +- src/Loaders/Loader.php | 4 +- src/Row.php | 10 ++- src/Transformers/UniqueRows.php | 20 +++-- tests/Unit/Database/StatementTest.php | 12 +-- tests/Unit/Extractors/AggregatorTest.php | 4 +- tests/Unit/Extractors/DateDimensionTest.php | 2 +- tests/Unit/Extractors/QueryTest.php | 73 ++++++++++++----- tests/Unit/Extractors/TableTest.php | 87 +++++++++++++++------ 11 files changed, 152 insertions(+), 71 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 20385a80..cd54c486 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,11 +10,9 @@ parameters: - message: '~^Variable method call on ~' path: src/Etl.php - - message: '~^Variable property access on ~' path: src/Row.php - - message: '~^Variable property access on ~' path: src/Step.php @@ -27,7 +25,4 @@ parameters: - message: '~Access to an undefined property Wizaplace\\Etl\\Row::\$name\.~' path: tests/Unit/RowTest.php - - - message: '~Method Wizaplace\\Etl\\Row::offsetGet\(\) has no return typehint specified.~' - path: src/Row.php diff --git a/src/Etl.php b/src/Etl.php index fde22144..f0727e95 100644 --- a/src/Etl.php +++ b/src/Etl.php @@ -44,7 +44,7 @@ public function __construct(Pipeline $pipeline = null) * * @return $this */ - public function extract(Extractor $extractor, $input, $options = []): Etl + public function extract(Extractor $extractor, mixed $input, $options = []): Etl { $extractor->input($input)->options($options); diff --git a/src/Loaders/InsertUpdate.php b/src/Loaders/InsertUpdate.php index b248fcdf..6c14703f 100644 --- a/src/Loaders/InsertUpdate.php +++ b/src/Loaders/InsertUpdate.php @@ -23,8 +23,10 @@ class InsertUpdate extends Insert /** * The primary key. + + * @var string[] */ - protected $key = ['id']; + protected array $key = ['id']; /** * Indicates if existing destination rows in table should be updated. diff --git a/src/Loaders/Loader.php b/src/Loaders/Loader.php index cc018b26..cca9ec0d 100644 --- a/src/Loaders/Loader.php +++ b/src/Loaders/Loader.php @@ -19,14 +19,14 @@ abstract class Loader extends Step /** * The loader output. */ - protected $output; + protected mixed $output; /** * Set the loader output. * * @return $this */ - public function output($output): Loader + public function output(mixed $output): Loader { $this->output = $output; diff --git a/src/Row.php b/src/Row.php index 1f8a8d12..74a57bb9 100644 --- a/src/Row.php +++ b/src/Row.php @@ -39,7 +39,7 @@ public function __construct(array $attributes) /** * Set a row attribute. */ - public function set(string $key, $value): self + public function set(string $key, mixed $value): self { $this->attributes[$key] = $value; @@ -48,6 +48,8 @@ public function set(string $key, $value): self /** * Get a row attribute. + * + * @return mixed */ public function get(string $key) { @@ -65,7 +67,7 @@ public function remove(string $key): void /** * Get a row attribute, and remove it. */ - public function pull(string $key) + public function pull(string $key): mixed { $value = $this->attributes[$key] ?? null; @@ -137,7 +139,7 @@ public function isIncomplete(): bool /** * Dynamically retrieve attributes on the row. */ - public function __get(string $key) + public function __get(string $key): mixed { return $this->attributes[$key]; } @@ -145,7 +147,7 @@ public function __get(string $key) /** * Dynamically set attributes on the row. */ - public function __set(string $key, $value): void + public function __set(string $key, mixed $value): void { $this->attributes[$key] = $value; } diff --git a/src/Transformers/UniqueRows.php b/src/Transformers/UniqueRows.php index 76747ab6..9e29fede 100644 --- a/src/Transformers/UniqueRows.php +++ b/src/Transformers/UniqueRows.php @@ -69,8 +69,10 @@ public function transform(Row $row): void /** * Prepare the given row for comparison. + * + * @return Row | string */ - protected function prepare(Row $row) + protected function prepare(Row $row): mixed { $row = $row->toArray(); @@ -78,22 +80,28 @@ protected function prepare(Row $row) $row = array_intersect_key($row, array_flip($this->columns)); } - return $this->consecutive ? $row : md5(serialize($row)); + return $this->consecutive + ? $row + : md5(serialize($row)); } /** * Verify if the subject is duplicate. */ - protected function isDuplicate($subject): bool + protected function isDuplicate(mixed $subject): bool { - return $this->consecutive ? $subject === $this->control : in_array($subject, $this->hashTable, true); + return $this->consecutive + ? $subject === $this->control + : in_array($subject, $this->hashTable, true); } /** * Register the subject for future comparison. */ - protected function register($subject): void + protected function register(mixed $subject): void { - $this->consecutive ? $this->control = $subject : $this->hashTable[] = $subject; + $this->consecutive + ? $this->control = $subject + : $this->hashTable[] = $subject; } } diff --git a/tests/Unit/Database/StatementTest.php b/tests/Unit/Database/StatementTest.php index 6204f24d..207cc156 100644 --- a/tests/Unit/Database/StatementTest.php +++ b/tests/Unit/Database/StatementTest.php @@ -98,13 +98,9 @@ public function prepareInvalid(): void $statement = new Statement($database); $statement->select('foo', ['>']); - try { - $statement->prepare(); - static::fail('An exception should have been thrown'); - } catch (\PDOException $exception) { - static::assertEquals('SQLSTATE[HY000]: General error: 1 no such table: foo', $exception->getMessage()); - } catch (\Exception $exception) { - static::fail('An instance of ' . \PDOException::class . ' should have been thrown'); - } + $this->expectExceptionObject( + new \PDOException('SQLSTATE[HY000]: General error: 1 no such table: foo') + ); + $statement->prepare(); } } diff --git a/tests/Unit/Extractors/AggregatorTest.php b/tests/Unit/Extractors/AggregatorTest.php index 1b01f632..48625cff 100644 --- a/tests/Unit/Extractors/AggregatorTest.php +++ b/tests/Unit/Extractors/AggregatorTest.php @@ -230,7 +230,7 @@ public static function iteratorsProvider(): array $simpleDataSet = [ [ - static::arrayToIterator([ + self::arrayToIterator([ ['id' => 1, 'name' => 'John Doe', 'email' => 'johndoe@email.com'], [], // should not happen ['impossible error'], // should not happen as well @@ -238,7 +238,7 @@ public static function iteratorsProvider(): array ['id' => 3, 'name' => 'Incomplete1', 'email' => 'incomplete1@dirtydata'], ['id' => 4, 'name' => 'Incomplete2', 'email' => 'incomplete2@dirtydata'], ]), - static::arrayToIterator([ + self::arrayToIterator([ ['email' => 'janedoe@email.com', 'twitter' => '@jane'], ['email' => 'johndoe@email.com', 'twitter' => '@john'], ['impossible error'], // should not happen as well diff --git a/tests/Unit/Extractors/DateDimensionTest.php b/tests/Unit/Extractors/DateDimensionTest.php index 2bcddb0c..b3d30d0b 100644 --- a/tests/Unit/Extractors/DateDimensionTest.php +++ b/tests/Unit/Extractors/DateDimensionTest.php @@ -205,7 +205,7 @@ public function defaultStart(): void $year = (int) $firstDay->format('Y'); $result = \iterator_to_array($extractor->extract()); - $firstRow = reset($result[0]); + $firstRow = reset($result); $lastRow = end($result); static::assertStringMatchesFormat( diff --git a/tests/Unit/Extractors/QueryTest.php b/tests/Unit/Extractors/QueryTest.php index f89bdcbe..c8486105 100644 --- a/tests/Unit/Extractors/QueryTest.php +++ b/tests/Unit/Extractors/QueryTest.php @@ -11,7 +11,9 @@ namespace Tests\Unit\Extractors; +use PHPUnit\Framework\MockObject\MockObject; use Tests\Tools\AbstractTestCase; +use Wizaplace\Etl\Database\Manager; use Wizaplace\Etl\Extractors\Query; use Wizaplace\Etl\Row; @@ -20,16 +22,32 @@ class QueryTest extends AbstractTestCase /** @test */ public function defaultOptions(): void { - $statement = $this->createMock('PDOStatement'); - $statement->expects(static::once())->method('execute')->with([]); - $statement->expects(static::exactly(3))->method('fetch') - ->will(static::onConsecutiveCalls(['row1'], ['row2'], null)); - - $connection = $this->createMock('PDO'); - $connection->expects(static::once())->method('prepare')->with('select query')->willReturn($statement); - - $manager = $this->createMock('Wizaplace\Etl\Database\Manager'); - $manager->expects(static::once())->method('pdo')->with('default')->willReturn($connection); + /** @var MockObject|\PDOStatement */ + $statement = $this->createMock(\PDOStatement::class); + $statement + ->expects(static::once()) + ->method('execute') + ->with([]); + $statement + ->expects(static::exactly(3)) + ->method('fetch') + ->willReturn(['row1'], ['row2'], null); + + /** @var MockObject|\PDO */ + $connection = $this->createMock(\PDO::class); + $connection + ->expects(static::once()) + ->method('prepare') + ->with('select query') + ->willReturn($statement); + + /** @var MockObject|Manager */ + $manager = $this->createMock(Manager::class); + $manager + ->expects(static::once()) + ->method('pdo') + ->with('default') + ->willReturn($connection); $extractor = new Query($manager); @@ -41,16 +59,33 @@ public function defaultOptions(): void /** @test */ public function customConnectionAndBindings(): void { - $statement = $this->createMock('PDOStatement'); - $statement->expects(static::once())->method('execute')->with(['binding']); - $statement->expects(static::exactly(3))->method('fetch') - ->will(static::onConsecutiveCalls(['row1'], ['row2'], null)); - - $connection = $this->createMock('PDO'); - $connection->expects(static::once())->method('prepare')->with('select query')->willReturn($statement); - $manager = $this->createMock('Wizaplace\Etl\Database\Manager'); - $manager->expects(static::once())->method('pdo')->with('connection')->willReturn($connection); + /** @var MockObject|\PDOStatement */ + $statement = $this->createMock(\PDOStatement::class); + $statement + ->expects(static::once()) + ->method('execute') + ->with(['binding']); + $statement + ->expects(static::exactly(3)) + ->method('fetch') + ->willReturn(['row1'], ['row2'], null); + + /** @var MockObject|\PDO */ + $connection = $this->createMock(\PDO::class); + $connection + ->expects(static::once()) + ->method('prepare') + ->with('select query') + ->willReturn($statement); + + /** @var MockObject|Manager */ + $manager = $this->createMock(Manager::class); + $manager + ->expects(static::once()) + ->method('pdo') + ->with('connection') + ->willReturn($connection); $extractor = new Query($manager); diff --git a/tests/Unit/Extractors/TableTest.php b/tests/Unit/Extractors/TableTest.php index 631e9afd..121d5eb8 100644 --- a/tests/Unit/Extractors/TableTest.php +++ b/tests/Unit/Extractors/TableTest.php @@ -11,10 +11,12 @@ namespace Tests\Unit\Extractors; +use PHPUnit\Framework\MockObject\MockObject; use Tests\Tools\AbstractTestCase; use Wizaplace\Etl; use Wizaplace\Etl\Database\ConnectionFactory; use Wizaplace\Etl\Database\Manager; +use Wizaplace\Etl\Database\Query; use Wizaplace\Etl\Extractors\Table; use Wizaplace\Etl\Row; @@ -23,17 +25,37 @@ class TableTest extends AbstractTestCase /** @test */ public function defaultOptions(): void { - $statement = $this->createMock('PDOStatement'); - $statement->expects(static::exactly(3))->method('fetch') - ->will(static::onConsecutiveCalls(['row1'], ['row2'], null)); - - $query = $this->createMock('Wizaplace\Etl\Database\Query'); - $query->expects(static::once())->method('select')->with('table', ['*'])->will(static::returnSelf()); - $query->expects(static::once())->method('where')->with([])->will(static::returnSelf()); - $query->expects(static::once())->method('execute')->willReturn($statement); - - $manager = $this->createMock('Wizaplace\Etl\Database\Manager'); - $manager->expects(static::once())->method('query')->with('default')->willReturn($query); + /** @var MockObject | \PDOStatement */ + $statement = $this->createMock(\PDOStatement::class); + $statement + ->expects(static::exactly(3)) + ->method('fetch') + ->willReturn(['row1'], ['row2'], null); + + /** @var MockObject | Query */ + $query = $this->createMock(Query::class); + $query + ->expects(static::once()) + ->method('select') + ->with('table', ['*']) + ->willReturnSelf(); + $query + ->expects(static::once()) + ->method('where') + ->with([]) + ->willReturnSelf(); + $query + ->expects(static::once()) + ->method('execute') + ->willReturn($statement); + + /** @var MockObject | Manager */ + $manager = $this->createMock(Manager::class); + $manager + ->expects(static::once()) + ->method('query') + ->with('default') + ->willReturn($query); $extractor = new Table($manager); @@ -45,17 +67,38 @@ public function defaultOptions(): void /** @test */ public function customConnectionColumnsAndWhereClause(): void { - $statement = $this->createMock('PDOStatement'); - $statement->expects(static::exactly(3))->method('fetch') - ->will(static::onConsecutiveCalls(['row1'], ['row2'], null)); - - $query = $this->createMock('Wizaplace\Etl\Database\Query'); - $query->expects(static::once())->method('select')->with('table', ['columns'])->will(static::returnSelf()); - $query->expects(static::once())->method('where')->with(['where'])->will(static::returnSelf()); - $query->expects(static::once())->method('execute')->willReturn($statement); - - $manager = $this->createMock('Wizaplace\Etl\Database\Manager'); - $manager->expects(static::once())->method('query')->with('connection')->willReturn($query); + /** @var MockObject | \PDOStatement */ + $statement = $this + ->createMock(\PDOStatement::class); + $statement + ->expects(static::exactly(3)) + ->method('fetch') + ->willReturn(['row1'], ['row2'], null); + + /** @var MockObject | Query */ + $query = $this->createMock(Query::class); + $query + ->expects(static::once()) + ->method('select') + ->with('table', ['columns']) + ->willReturnSelf(); + $query + ->expects(static::once()) + ->method('where') + ->with(['where']) + ->willReturnSelf(); + $query + ->expects(static::once()) + ->method('execute') + ->willReturn($statement); + + /** @var MockObject | Manager */ + $manager = $this->createMock(Manager::class); + $manager + ->expects(static::once()) + ->method('query') + ->with('connection') + ->willReturn($query); $extractor = new Table($manager); From 4199cbecceba0d5b686721155e3e76f232cb22db Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 12:17:08 +0200 Subject: [PATCH 15/19] fix: phpcsfixer --- src/Loaders/InsertUpdate.php | 2 +- src/Row.php | 4 +--- src/Transformers/UniqueRows.php | 4 ++-- tests/Unit/Extractors/QueryTest.php | 1 - tests/Unit/Extractors/TableTest.php | 12 ++++++------ 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Loaders/InsertUpdate.php b/src/Loaders/InsertUpdate.php index 6c14703f..0936dd4c 100644 --- a/src/Loaders/InsertUpdate.php +++ b/src/Loaders/InsertUpdate.php @@ -23,7 +23,7 @@ class InsertUpdate extends Insert /** * The primary key. - + * * @var string[] */ protected array $key = ['id']; diff --git a/src/Row.php b/src/Row.php index 74a57bb9..7ce86836 100644 --- a/src/Row.php +++ b/src/Row.php @@ -48,10 +48,8 @@ public function set(string $key, mixed $value): self /** * Get a row attribute. - * - * @return mixed */ - public function get(string $key) + public function get(string $key): mixed { return $this->attributes[$key] ?? null; } diff --git a/src/Transformers/UniqueRows.php b/src/Transformers/UniqueRows.php index 9e29fede..e0848fc7 100644 --- a/src/Transformers/UniqueRows.php +++ b/src/Transformers/UniqueRows.php @@ -69,8 +69,8 @@ public function transform(Row $row): void /** * Prepare the given row for comparison. - * - * @return Row | string + * + * @return Row|string */ protected function prepare(Row $row): mixed { diff --git a/tests/Unit/Extractors/QueryTest.php b/tests/Unit/Extractors/QueryTest.php index c8486105..340c9b41 100644 --- a/tests/Unit/Extractors/QueryTest.php +++ b/tests/Unit/Extractors/QueryTest.php @@ -59,7 +59,6 @@ public function defaultOptions(): void /** @test */ public function customConnectionAndBindings(): void { - /** @var MockObject|\PDOStatement */ $statement = $this->createMock(\PDOStatement::class); $statement diff --git a/tests/Unit/Extractors/TableTest.php b/tests/Unit/Extractors/TableTest.php index 121d5eb8..0fe184d2 100644 --- a/tests/Unit/Extractors/TableTest.php +++ b/tests/Unit/Extractors/TableTest.php @@ -25,14 +25,14 @@ class TableTest extends AbstractTestCase /** @test */ public function defaultOptions(): void { - /** @var MockObject | \PDOStatement */ + /** @var MockObject|\PDOStatement */ $statement = $this->createMock(\PDOStatement::class); $statement ->expects(static::exactly(3)) ->method('fetch') ->willReturn(['row1'], ['row2'], null); - /** @var MockObject | Query */ + /** @var MockObject|Query */ $query = $this->createMock(Query::class); $query ->expects(static::once()) @@ -49,7 +49,7 @@ public function defaultOptions(): void ->method('execute') ->willReturn($statement); - /** @var MockObject | Manager */ + /** @var MockObject|Manager */ $manager = $this->createMock(Manager::class); $manager ->expects(static::once()) @@ -67,7 +67,7 @@ public function defaultOptions(): void /** @test */ public function customConnectionColumnsAndWhereClause(): void { - /** @var MockObject | \PDOStatement */ + /** @var MockObject|\PDOStatement */ $statement = $this ->createMock(\PDOStatement::class); $statement @@ -75,7 +75,7 @@ public function customConnectionColumnsAndWhereClause(): void ->method('fetch') ->willReturn(['row1'], ['row2'], null); - /** @var MockObject | Query */ + /** @var MockObject|Query */ $query = $this->createMock(Query::class); $query ->expects(static::once()) @@ -92,7 +92,7 @@ public function customConnectionColumnsAndWhereClause(): void ->method('execute') ->willReturn($statement); - /** @var MockObject | Manager */ + /** @var MockObject|Manager */ $manager = $this->createMock(Manager::class); $manager ->expects(static::once()) From 5ad0a919cc3028a4c26e2093f8fb919586c6b38b Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 15:22:11 +0200 Subject: [PATCH 16/19] fix: phpstan Rox variable property access --- phpstan.neon.dist | 3 --- src/Row.php | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index cd54c486..ca9f7af8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,9 +10,6 @@ parameters: - message: '~^Variable method call on ~' path: src/Etl.php - - - message: '~^Variable property access on ~' - path: src/Row.php - message: '~^Variable property access on ~' path: src/Step.php diff --git a/src/Row.php b/src/Row.php index 7ce86836..a474b55e 100644 --- a/src/Row.php +++ b/src/Row.php @@ -86,7 +86,7 @@ public function transform(array $columns, callable $callback): void } foreach ($columns as $column) { - $this->$column = $callback($this->$column); + $this->attributes[$column] = $callback($this->attributes[$column]); } } From 5b264975c56793fd675364ed5b41a55f9adfe1b6 Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Fri, 8 Sep 2023 15:23:28 +0200 Subject: [PATCH 17/19] fix: phpstan XmReader::open() --- phpstan.neon.dist | 3 --- src/Extractors/Xml.php | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ca9f7af8..0aca2b70 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -13,9 +13,6 @@ parameters: - message: '~^Variable property access on ~' path: src/Step.php - - - message: '~^Dynamic call to static method XMLReader::open\(\)\.~' - path: src/Extractors\Xml.php - message: '~Variable method call on Wizaplace\\Etl\\Step\.~' path: tests/Tools/AbstractTestCase.php diff --git a/src/Extractors/Xml.php b/src/Extractors/Xml.php index 881d144d..4584d4f7 100644 --- a/src/Extractors/Xml.php +++ b/src/Extractors/Xml.php @@ -58,9 +58,7 @@ public function extract(): \Generator $value = $this->loop . $value; } - $this->reader = new \XMLReader(); - - $this->reader->open($this->input); + $this->reader = \XMLReader::open($this->input); while ($this->reader->read()) { $this->addElementToPath(); From fad65cb96e66b129919b094c527ab1470b7e78ee Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Sun, 10 Sep 2023 13:23:39 +0200 Subject: [PATCH 18/19] docs: update changelog.MD --- changelog.MD | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/changelog.MD b/changelog.MD index c4a0083f..01a66d48 100644 --- a/changelog.MD +++ b/changelog.MD @@ -1,5 +1,14 @@ # Changelog +## Next version + +**Bugfixes** +* Use backticks `` ` `` for table and column names in `Wizaplace\Etl\Database\*` classes (see https://github.com/wizacode/php-etl/issues/117) + +**Miscellaneous** +* Nix shell dev environment `Makefile` command +* Code coverage `Makefile` command + ## 2.3 * Add the PHPDoc _@mixin Pipeline_ to the Etl class. * Add _mixed_ return type to _Wizaplace\Etl\Row\offsetGet_. From 4c798f4bdc6f71c8cc31e0dc3035601a3601d4fc Mon Sep 17 00:00:00 2001 From: Merleur l'Enchantain Date: Mon, 11 Sep 2023 05:13:32 +0200 Subject: [PATCH 19/19] fix: ignoreMask in Helpers::implode --- docs/img/etl.svg | 66 ++++++++++++++-------------- src/Database/Helpers.php | 18 +++++--- tests/Unit/Database/HelpersTest.php | 67 +++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 38 deletions(-) create mode 100644 tests/Unit/Database/HelpersTest.php diff --git a/docs/img/etl.svg b/docs/img/etl.svg index 53524f1e..fdb70833 100644 --- a/docs/img/etl.svg +++ b/docs/img/etl.svg @@ -321,9 +321,9 @@ id="text896-3" y="-90.151337" x="35.713844" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.05555582px;line-height:1.25;font-family:'Roboto Slab';-inkscape-font-specification:'Roboto Slab';text-align:justify;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:url(#fond);fill-opacity:1;stroke:none;stroke-width:0.52916664" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.05555582px;line-height:1.25;font-family:'sans-serif';-inkscape-font-specification:'sans-serif';text-align:justify;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:url(#fond);fill-opacity:1;stroke:none;stroke-width:0.52916664" xml:space="preserve"> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Monospace';-inkscape-font-specification:'Monospace';stroke-width:0.26458332" /> @@ -398,7 +398,7 @@ style="opacity:1;fill:url(#extractor);fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> Extractor + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4px;font-family:'Monospace';-inkscape-font-specification:'Monospace';fill:url(#fond);stroke-width:0.26458332">Extractor Transformer + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4px;font-family:'Monospace';-inkscape-font-specification:'Monospace';text-align:end;text-anchor:end;fill:url(#fond);stroke-width:0.26458332">Transformer ASSETS COLORS + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Monospace';-inkscape-font-specification:'Monospace';fill:url(#bordure);stroke-width:1.19711387">COLORS Json + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.86666679px;font-family:'Monospace';-inkscape-font-specification:'Monospace';fill:url(#fond);stroke-width:0.52916664">Json [ + [ + ['*'], + '`{column}`', + ], + '*', + ], + 'do not backtick * in a list' => [ + [ + ['*', 'other'], + '`{column}`', + ], + '*, `other`', + ], + 'backtick * if not in ignoreMask' => [ + [ + ['*', 'other'], + '`{column}`', + ['other'], + ], + '`*`, other', + ], + 'common' => [ + [ + ['hello', 'world'], + '#{column}#', + ], + '#hello#, #world#', + ], + 'default' => [ + [ + ['hello', 'world'], + ], + 'hello, world', + ], + ]; + } +}