Skip to content

Commit

Permalink
Updated changelog and upgrade instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
sad-spirit committed Jan 14, 2025
1 parent 2d199e1 commit 29b3b6e
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 65 deletions.
16 changes: 11 additions & 5 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ please consult the [upgrade instructions](./Upgrading.md).
* `json_exists()`, `json_query()`, `json_value()` for querying JSON data using jsonpath expressions.
Represented by `nodes\json\JsonExists`, `nodes\json\JsonQuery`,
`nodes\json\JsonValue`, respectively.
* `json_table()` allows JSON data to be converted into a relational view and used a FROM clause,
* `json_table()` allows JSON data to be converted into a relational view and used in a `FROM` clause,
represented by `nodes\range\JsonTable` and related classes.
* `MERGE` statement improvements
* It is now possible to use `MERGE` statements in `WITH` clauses.
Expand All @@ -33,20 +33,23 @@ please consult the [upgrade instructions](./Upgrading.md).

### Changed
* Consistently follow Postgres 17 in what is considered a whitespace character: space, `\r`, `\n`, `\t`, `\v`, `\f`.
* Native `public readonly` properties are used in `nodes\Identifier`, `nodes\expressions\Constant`,
`nodes\expressions\Parameter`, and their subclasses instead of magic ones.
* Enums are used throughout package instead of string constants, see the [upgrade instructions](Upgrading.md).
* Added typehints for arguments and return values where not previously possible,
e.g. `self|string|ScalarExpression|null` for an argument of `nodes\WhereOrHavingClause::and()`.
* `Token` class was converted to an interface with several implementations
* Arguments for setter methods no longer have default (usually `null`) values. These values should be passed
explicitly, though the recommended way is to use magic properties rather than setters.
* Native `public readonly` properties are used in `nodes\Identifier`, `nodes\expressions\Constant`,
`nodes\expressions\Parameter`, and their subclasses instead of magic ones.
* `Token` class was converted to an interface with several implementations.

### Removed

* Features deprecated in 2.x releases were removed:
* `ParserAwareTypeConverterFactory` class, `BuilderSupportDecorator` should be used instead.
* `$resultTypes` parameter for `NativeStatement::executePrepared()`. The types should be
passed to `NativeStatement::prepare()`.
* `Node` classes no longer implement deprecated `Serializable` interface.
* `nodes\GenericNode` no longer implements deprecated `Serializable` interface, `serialize()` and
`unserialize()` methods were removed from it and its subclasses.
* `Keywords` class (replaced by `Keyword` enum, see the [upgrade instructions](Upgrading.md)).

### Fixed
Expand All @@ -58,6 +61,9 @@ please consult the [upgrade instructions](./Upgrading.md).
in such a way, e.g. `SELECT NULL AND` (this returns a null column aliased `and` in Postgres).
* Lexer matches a complete identifier in "junk after number" tests. Previously only a single byte was matched,
so the error message could possibly contain a partial multibyte character. Same fix as in Postgres 17.
* `nodes\json\JsonArrayAgg` and `nodes\json\JsonObjectAgg` no longer implement `FunctionLike` as they cannot be used
in `FROM` clause. An exception will be thrown if they (or the new `nodes\expressions\MergeAction`) appear when
parsing the `FROM` clause.

## [2.4.0] - 2024-05-27

Expand Down
207 changes: 147 additions & 60 deletions Upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
The main user-facing issues are
* Classes supporting integration with `sad_spirit\pg_wrapper` had deprecated features removed;
* Public properties of several `Node` implementations changed type from `string` to enums;
* Removed default values for setter method arguments;
* Additional typehints, especially for `TreeWalker`.

The changes to classes used in `Lexer` and `Parser` are documented for completeness.
The changes to classes used in `Lexer` and `Parser` are documented for completeness but are unlikely to cause issues.

## Removed features
* Features deprecated in 2.x releases were removed
Expand Down Expand Up @@ -35,62 +36,6 @@ The changes to classes used in `Lexer` and `Parser` are documented for completen
* `$format` property and constructor argument for `nodes\json\JsonFormat` as it is currently hardcoded to `json`.
* `Keywords` class. Replaced by `Keyword` enum, see below.

## Changed `Parser`-related features

### `Token` class -> interface

`Token` class was converted to an interface with several implementations:
* Abstract `tokens\GenericToken`
* `tokens\EOFToken` signalling end of input;
* `tokens\KeywordToken` representing a keyword;
* `tokens\StringToken` having a type and a string value - basically anything that is not a keyword.

`Token::TYPE_` constants are now represented by cases of `TokenType` enum, `Token::typeToString()` is replaced by
`TokenType::toString`.

Before:
```PHP
$identifier = new Token(Token::TYPE_IDENTIFIER, 'foo', 123);
$keyword = new Token(Token::TYPE_RESERVED_KEYWORD, 'default', 456);
```
now:
```PHP
$identifier = new StringToken(TokenType::IDENTIFIER, 'foo', 123);
$keyword = new KeywordToken(Keyword::DEFAULT, 456);
```

### `Keywords` class -> `Keyword` enum

Postgres keywords are now represented as cases of `Keyword` enum rather than as string literals. Features that were
previously available in `Keywords` class are now in this enum.
* Checking whether the given string represents a keyword, before:
```PHP
if (Keywords::isKeyword('select')) {
// process keyword
}
```
now (using standard backed enum method):
```PHP
if (null !== Keyword::tryFrom('select')) {
// process keyword
}
```
* Getting the type of the keyword, before:
```PHP
$type = Keywords::LIST['select'][0]; // Token::TYPE_RESERVED_KEYWORD
```
now:
```PHP
$type = Keyword::SELECT->getType(); // TokenType::RESERVED_KEYWORD
```
* Checking whether the keyword can be used as a column alias without `AS`, before:
```PHP
Keywords::isBareLabelKeyword('and');
```
now:
```PHP
Keyword::AND->isBareLabel();
```

## Conversion of string properties to enums

Expand All @@ -107,7 +52,7 @@ enum IntervalMask: string
}
```
These backing values correspond to the strings that were accepted by `Node` classes and the case names correspond to
constants that were previously defined in these classes, so migration is simple enough. If using string literals,
constants that were previously defined in these classes, so migration is simple enough. Using string literals,
before:
```PHP
$node = new SQLValueFunction('current_schema');
Expand All @@ -116,7 +61,7 @@ now:
```PHP
$node = new SQLValueFunction(SQLValueFunctionName::from('current_schema'))
```
If using constants, before:
Using constants, before:
```PHP
$node = new SQLValueFunction(SQLValueFunction::CURRENT_DATE);
```
Expand All @@ -125,11 +70,21 @@ now:
$node = new SQLValueFunction(SQLValueFunctionName::CURRENT_DATE);
```

When reading an enum-backed property, its `$value` property should be used if string representation is needed. Before:
```PHP
// prints e.g. 'exists'
echo $subselect->operator;
```
now:
```PHP
echo $subselect->operator->value;
```



The following properties/arguments were converted:

* `Insert`: `$overriding` property is `enums\InsertOverriding`.
* `Insert`: `$overriding` property is now a case of `enums\InsertOverriding`.
* `SetOpSelect`: `$operator` property and constructor argument is `enums\SetOperator`.
* `nodes\IndexElement`: `$direction` property and `$direction` argument for constructor
is `enums\IndexElementDirection`; `$nullsOrder` property and constructor
Expand Down Expand Up @@ -172,3 +127,135 @@ The following properties/arguments were converted:

Additionally
* `nodes\range\FromElement`: `$joinType` argument to `join()` is now `enums\JoinType`

## Removed default values for arguments of setter methods

Implicitly nullable parameters were [deprecated in PHP 8.4](https://www.php.net/manual/en/migration84.deprecated.php),
thus argument typehints were changed to explicitly nullable and their default `null` values were removed,
```PHP
$bar->setFoo();
```
looks weird unlike more explicit
```PHP
$bar->setFoo(null);
```
Some of the setter methods had defaults other than `null`, these were also removed.

Note that it was never recommended to directly call the below methods, except `Node::setParentNode()`:
they are currently used to support writable magic properties, but that implementation detail may change.
```PHP
// Calling setter method, not recommended
$select->setLimit('10')
// Setting the property is the recommended way
$select->limit = '10';
```


Methods that changed signatures:

* `Node` (and all its implementations)
* `public function setParentNode(Node $parent = null): void` -> `public function setParentNode(?Node $parent): void`
* `Insert`:
* `public function setValues(SelectCommon $values = null): void` -> `public function setValues(?SelectCommon $values): void`
* `public function setOnConflict($onConflict = null): void` -> `public function setOnConflict(string|OnConflictClause|null $onConflict): void`
* `public function setOverriding(?string $overriding = null): void` -> `public function setOverriding(?InsertOverriding $overriding): void`
* `SelectCommon`
* `public function setLimit($limit = null): void` -> `public function setLimit(string|ScalarExpression|null $limit): void`
* `public function setOffset($offset = null): void` -> `public function setOffset(string|ScalarExpression|null $offset): void`
* `nodes\ArrayIndexes`
* `public function setLower(ScalarExpression $lower = null): void` -> `public function setLower(?ScalarExpression $lower): void`
* `public function setUpper(ScalarExpression $upper = null): void` -> `public function setUpper(?ScalarExpression $upper): void`
* `nodes\IntervalTypeName`
* `public function setMask(string $mask = ''): void` -> `public function setMask(?IntervalMask $mask): void`
* `nodes\OnConflictClause`
* `public function setTarget(Node $target = null): void` -> `public function setTarget(IndexParameters|Identifier|null $target): void`
* `nodes\TypeName`
* `public function setSetOf(bool $setOf = false): void` -> `public function setSetOf(bool $setOf): void`
* `nodes\WhereOrHavingClause`
* `public function setCondition($condition = null): self` -> `public function setCondition(string|null|self|ScalarExpression $condition): self`
* `nodes\WindowDefinition`
* `public function setName(Identifier $name = null): void` -> `public function setName(?Identifier $name): void`
* `nodes\WindowFrameBound`
* `public function setValue(ScalarExpression $value = null): void` -> `public function setValue(?ScalarExpression $value): void`
* `nodes\expressions\CaseExpression`
* `public function setArgument(ScalarExpression $argument = null): void` -> `public function setArgument(?ScalarExpression $argument): void`
* `public function setElse(ScalarExpression $elseClause = null): void` -> `public function setElse(?ScalarExpression $elseClause): void`
* `nodes\expressions\OperatorExpression`
* `public function setLeft(ScalarExpression $left = null): void` -> `public function setLeft(?ScalarExpression $left): void`
* `nodes\expressions\PatternMatchingExpression`
* `public function setEscape(ScalarExpression $escape = null): void` -> `public function setEscape(?ScalarExpression $escape): void`
* `nodes\merge\MergeInsert`
* `public function setOverriding(?string $overriding = null): void` -> `public function setOverriding(?InsertOverriding $overriding): void`
* `nodes\range\FromElement` (and subclasses)
* `public function setAlias(Identifier $tableAlias = null, NodeList $columnAliases = null): void`
-> `public function setAlias(?Identifier $tableAlias, ?NodeList $columnAliases = null): void`
* `nodes\range\JoinExpression`
* `public function setUsing($using = null): void` -> `public function setUsing(null|string|iterable|UsingClause $using): void`
* `public function setOn($on = null): void` -> `public function setOn(null|string|ScalarExpression $on): void`
* `nodes\range\TableSample`
* `public function setRepeatable(ScalarExpression $repeatable = null): void` -> `public function setRepeatable(?ScalarExpression $repeatable): void`
* `nodes\xml\XmlNamespace`
* `public function setAlias(Identifier $alias = null): void` -> `public function setAlias(?Identifier $alias): void`
* `nodes\xml\XmlRoot`
* `public function setVersion(ScalarExpression $version = null): void` -> `public function setVersion(?ScalarExpression $version): void`
* `nodes\xml\XmlTypedColumnDefinition`
* `public function setPath(ScalarExpression $path = null): void` -> `public function setPath(?ScalarExpression $path): void`
* `public function setNullable(?bool $nullable = null): void` -> `public function setNullable(?bool $nullable): void`
* `public function setDefault(ScalarExpression $default = null): void` -> `public function setDefault(?ScalarExpression $default): void`

## Changed `Parser`-related features

### `Token` class -> interface

`Token` class was converted to an interface with several implementations:
* Abstract `tokens\GenericToken`
* `tokens\EOFToken` signalling end of input;
* `tokens\KeywordToken` representing a keyword;
* `tokens\StringToken` having a type and a string value - basically anything that is not a keyword.

`Token::TYPE_` constants are now represented by cases of `TokenType` enum, `Token::typeToString()` is replaced by
`TokenType::toString()`.

Before:
```PHP
$identifier = new Token(Token::TYPE_IDENTIFIER, 'foo', 123);
$keyword = new Token(Token::TYPE_RESERVED_KEYWORD, 'default', 456);
```
now:
```PHP
$identifier = new StringToken(TokenType::IDENTIFIER, 'foo', 123);
$keyword = new KeywordToken(Keyword::DEFAULT, 456);
```

### `Keywords` class -> `Keyword` enum

Postgres keywords are now represented as cases of `Keyword` enum rather than as string literals. Features that were
previously available in `Keywords` class are now in this enum.
* Checking whether the given string represents a keyword, before:
```PHP
if (Keywords::isKeyword('select')) {
// process keyword
}
```
now (using standard backed enum method):
```PHP
if (null !== Keyword::tryFrom('select')) {
// process keyword
}
```
* Getting the type of the keyword, before:
```PHP
$type = Keywords::LIST['select'][0]; // Token::TYPE_RESERVED_KEYWORD
```
now:
```PHP
$type = Keyword::SELECT->getType(); // TokenType::RESERVED_KEYWORD
```
* Checking whether the keyword can be used as a column alias without `AS`, before:
```PHP
Keywords::isBareLabelKeyword('and');
```
now:
```PHP
Keyword::AND->isBareLabel();
```

0 comments on commit 29b3b6e

Please sign in to comment.