From ac5879a5187c5d60432e171c2def515cd8baa36d Mon Sep 17 00:00:00 2001 From: Alexey Borzov Date: Tue, 29 Aug 2023 09:42:15 +0300 Subject: [PATCH] Added `[NO] INDENT` option for `XMLSERIALIZE()` --- Changelog.md | 1 + src/sad_spirit/pg_builder/Parser.php | 8 +++++++- src/sad_spirit/pg_builder/SqlBuilderWalker.php | 3 ++- .../pg_builder/nodes/xml/XmlSerialize.php | 18 ++++++++++++++++-- tests/ParseFunctionCallTest.php | 5 +++-- tests/SqlBuilderTest.php | 2 +- 6 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Changelog.md b/Changelog.md index 8f555f7..521c4a2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,6 +12,7 @@ Support new syntax of PostgreSQL 16 (as of beta 3) * Constructor functions `json_array()` and `json_object()` represented by `nodes\json\JsonArrayValueList`, `nodes\json\JsonArraySubselect`, `nodes\json\JsonObject` classes. * `SYSTEM_USER` server variable backed by `nodes\expressions\SQLValueFunction`. + * `[NO] INDENT` option for `XMLSERIALIZE()` expression. ## [2.2.0] - 2023-05-14 diff --git a/src/sad_spirit/pg_builder/Parser.php b/src/sad_spirit/pg_builder/Parser.php index 08590a5..3519267 100644 --- a/src/sad_spirit/pg_builder/Parser.php +++ b/src/sad_spirit/pg_builder/Parser.php @@ -2805,7 +2805,13 @@ protected function SystemFunctionCallRequiredParens(): ?nodes\FunctionLike $value = $this->Expression(); $this->stream->expect(Token::TYPE_KEYWORD, 'as'); $typeName = $this->SimpleTypeName(); - $funcNode = new nodes\xml\XmlSerialize($docOrContent, $value, $typeName); + $indent = null; + if ($this->stream->matchesKeyword(['no', 'indent'])) { + if (!($indent = ('indent' === $this->stream->next()->getValue()))) { + $this->stream->expect(Token::TYPE_KEYWORD, 'indent'); + } + } + $funcNode = new nodes\xml\XmlSerialize($docOrContent, $value, $typeName, $indent); break; case 'normalize': diff --git a/src/sad_spirit/pg_builder/SqlBuilderWalker.php b/src/sad_spirit/pg_builder/SqlBuilderWalker.php index 2d434f1..06c03c4 100644 --- a/src/sad_spirit/pg_builder/SqlBuilderWalker.php +++ b/src/sad_spirit/pg_builder/SqlBuilderWalker.php @@ -1327,7 +1327,8 @@ public function walkXmlRoot(nodes\xml\XmlRoot $xml): string public function walkXmlSerialize(nodes\xml\XmlSerialize $xml): string { return 'xmlserialize(' . $xml->documentOrContent . ' ' . $xml->argument->dispatch($this) - . ' as ' . $xml->type->dispatch($this) . ')'; + . ' as ' . $xml->type->dispatch($this) + . (null === $xml->indent ? '' : ($xml->indent ? ' indent' : ' no indent')) . ')'; } public function walkXmlTable(nodes\range\XmlTable $table): string diff --git a/src/sad_spirit/pg_builder/nodes/xml/XmlSerialize.php b/src/sad_spirit/pg_builder/nodes/xml/XmlSerialize.php index 786e528..217e575 100644 --- a/src/sad_spirit/pg_builder/nodes/xml/XmlSerialize.php +++ b/src/sad_spirit/pg_builder/nodes/xml/XmlSerialize.php @@ -36,6 +36,7 @@ * @property-read string $documentOrContent * @property ScalarExpression $argument * @property-read TypeName $type + * @property bool|null $indent */ class XmlSerialize extends GenericNode implements ScalarExpression, FunctionLike { @@ -55,9 +56,15 @@ class XmlSerialize extends GenericNode implements ScalarExpression, FunctionLike protected $p_argument; /** @var TypeName */ protected $p_type; + /** @var bool|null */ + protected $p_indent; - public function __construct(string $documentOrContent, ScalarExpression $argument, TypeName $typeName) - { + public function __construct( + string $documentOrContent, + ScalarExpression $argument, + TypeName $typeName, + ?bool $indent = null + ) { if (!isset(self::ALLOWED_TYPES[$documentOrContent])) { throw new InvalidArgumentException( "Either 'document' or 'content' option required, '{$documentOrContent}' given" @@ -72,6 +79,8 @@ public function __construct(string $documentOrContent, ScalarExpression $argumen $this->p_type = $typeName; $this->p_type->setParentNode($this); + + $this->p_indent = $indent; } public function setArgument(ScalarExpression $argument): void @@ -79,6 +88,11 @@ public function setArgument(ScalarExpression $argument): void $this->setRequiredProperty($this->p_argument, $argument); } + public function setIndent(?bool $indent): void + { + $this->p_indent = $indent; + } + public function dispatch(TreeWalker $walker) { return $walker->walkXmlSerialize($this); diff --git a/tests/ParseFunctionCallTest.php b/tests/ParseFunctionCallTest.php index 76ac9e1..0926eb5 100644 --- a/tests/ParseFunctionCallTest.php +++ b/tests/ParseFunctionCallTest.php @@ -379,9 +379,10 @@ public function testXmlSerialize(): void new XmlSerialize( 'document', new ColumnReference('foo'), - new TypeName(new QualifiedName('pg_catalog', 'text')) + new TypeName(new QualifiedName('pg_catalog', 'text')), + true ), - $this->parser->parseExpression('xmlserialize(document foo as pg_catalog.text)') + $this->parser->parseExpression('xmlserialize(document foo as pg_catalog.text indent)') ); } diff --git a/tests/SqlBuilderTest.php b/tests/SqlBuilderTest.php index 2d04ed7..3839ed8 100644 --- a/tests/SqlBuilderTest.php +++ b/tests/SqlBuilderTest.php @@ -153,7 +153,7 @@ public function testBuildSelectStatement(): void xmlparse(document xml.doc preserve whitespace), xmlpi(name php, 'echo ''Hello world!'';'), xmlroot(doc, version '1.2', standalone yes), - xmlserialize(document foo as pg_catalog.text) + xmlserialize(document foo as pg_catalog.text indent) ), fnstuff as materialized ( select s.num,