packages/ztd-query-postgres/tests/Unit/Sql/Value/PgSqlCastRendererTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Sql\Value;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use ZtdQuery\Platform\Postgres\Sql\Value\PgSqlCastRenderer;
9use ZtdQuery\Schema\ColumnDeclaration;
10use ZtdQuery\Schema\ColumnTypeFamily;
11
12#[CoversClass(PgSqlCastRenderer::class)]
13#[CoversClass(\ZtdQuery\Platform\Postgres\Sql\Value\CastTypeMapper::class)]
14#[\PHPUnit\Framework\Attributes\UsesClass(\ZtdQuery\Platform\Postgres\Sql\Value\NativeCastTarget::class)]
15final class PgSqlCastRendererTest extends \PHPUnit\Framework\TestCase
16{
17    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::INTEGER, 'INTEGER'])]
18    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::FLOAT, 'REAL'])]
19    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DOUBLE, 'DOUBLE PRECISION'])]
20    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)'])]
21    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::STRING, 'VARCHAR(255)'])]
22    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TEXT, 'TEXT'])]
23    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BOOLEAN, 'BOOLEAN'])]
24    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATE, 'DATE'])]
25    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIME, 'TIME'])]
26    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATETIME, 'TIMESTAMP'])]
27    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIMESTAMP, 'TIMESTAMPTZ'])]
28    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BINARY, 'BYTEA'])]
29    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::JSON, 'JSONB'])]
30    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::UNKNOWN, 'UUID'])]
31    public function testRenderCastReturnsNonEmptyString(ColumnTypeFamily $family, string $nativeType): void
32    {
33        $renderer = new PgSqlCastRenderer();
34        $type = new ColumnDeclaration($family, $nativeType);
35        $result = $renderer->renderCast("'test'", $type);
36        self::assertNotEmpty($result, sprintf('renderCast returned empty string for family %s', $family->value));
37    }
38    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::INTEGER, 'INTEGER'])]
39    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::FLOAT, 'REAL'])]
40    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DOUBLE, 'DOUBLE PRECISION'])]
41    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)'])]
42    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::STRING, 'VARCHAR(255)'])]
43    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TEXT, 'TEXT'])]
44    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BOOLEAN, 'BOOLEAN'])]
45    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATE, 'DATE'])]
46    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIME, 'TIME'])]
47    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATETIME, 'TIMESTAMP'])]
48    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIMESTAMP, 'TIMESTAMPTZ'])]
49    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BINARY, 'BYTEA'])]
50    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::JSON, 'JSONB'])]
51    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::UNKNOWN, 'UUID'])]
52    public function testRenderNullCastReturnsNonEmptyString(ColumnTypeFamily $family, string $nativeType): void
53    {
54        $renderer = new PgSqlCastRenderer();
55        $type = new ColumnDeclaration($family, $nativeType);
56        $result = $renderer->renderNullCast($type);
57        self::assertNotEmpty($result, sprintf('renderNullCast returned empty string for family %s', $family->value));
58    }
59    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::INTEGER, 'INTEGER'])]
60    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::FLOAT, 'REAL'])]
61    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DOUBLE, 'DOUBLE PRECISION'])]
62    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)'])]
63    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::STRING, 'VARCHAR(255)'])]
64    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TEXT, 'TEXT'])]
65    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BOOLEAN, 'BOOLEAN'])]
66    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATE, 'DATE'])]
67    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIME, 'TIME'])]
68    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATETIME, 'TIMESTAMP'])]
69    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIMESTAMP, 'TIMESTAMPTZ'])]
70    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BINARY, 'BYTEA'])]
71    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::JSON, 'JSONB'])]
72    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::UNKNOWN, 'UUID'])]
73    public function testRenderNullCastContainsCastKeyword(ColumnTypeFamily $family, string $nativeType): void
74    {
75        $renderer = new PgSqlCastRenderer();
76        $type = new ColumnDeclaration($family, $nativeType);
77        $result = $renderer->renderNullCast($type);
78        self::assertStringContainsString('CAST(', strtoupper($result), sprintf('renderNullCast output for family %s does not contain CAST(', $family->value));
79    }
80    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::INTEGER, 'INTEGER'])]
81    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::FLOAT, 'REAL'])]
82    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DOUBLE, 'DOUBLE PRECISION'])]
83    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)'])]
84    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::STRING, 'VARCHAR(255)'])]
85    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TEXT, 'TEXT'])]
86    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BOOLEAN, 'BOOLEAN'])]
87    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATE, 'DATE'])]
88    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIME, 'TIME'])]
89    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATETIME, 'TIMESTAMP'])]
90    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIMESTAMP, 'TIMESTAMPTZ'])]
91    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BINARY, 'BYTEA'])]
92    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::JSON, 'JSONB'])]
93    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::UNKNOWN, 'UUID'])]
94    public function testRenderNullCastContainsNullKeyword(ColumnTypeFamily $family, string $nativeType): void
95    {
96        $renderer = new PgSqlCastRenderer();
97        $type = new ColumnDeclaration($family, $nativeType);
98        $result = $renderer->renderNullCast($type);
99        self::assertStringContainsString('NULL', strtoupper($result), sprintf('renderNullCast output for family %s does not contain NULL', $family->value));
100    }
101    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::INTEGER, 'INTEGER'])]
102    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::FLOAT, 'REAL'])]
103    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DOUBLE, 'DOUBLE PRECISION'])]
104    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)'])]
105    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::STRING, 'VARCHAR(255)'])]
106    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TEXT, 'TEXT'])]
107    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BOOLEAN, 'BOOLEAN'])]
108    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATE, 'DATE'])]
109    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIME, 'TIME'])]
110    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::DATETIME, 'TIMESTAMP'])]
111    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::TIMESTAMP, 'TIMESTAMPTZ'])]
112    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::BINARY, 'BYTEA'])]
113    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::JSON, 'JSONB'])]
114    #[\PHPUnit\Framework\Attributes\TestWith([ColumnTypeFamily::UNKNOWN, 'UUID'])]
115    public function testAllColumnTypeFamiliesHandled(ColumnTypeFamily $family, string $nativeType): void
116    {
117        $renderer = new PgSqlCastRenderer();
118        $type = new ColumnDeclaration($family, $nativeType);
119        $castResult = $renderer->renderCast("'value'", $type);
120        $nullResult = $renderer->renderNullCast($type);
121        self::assertNotEmpty($castResult, sprintf('renderCast returned empty for family %s', $family->value));
122        self::assertNotEmpty($nullResult, sprintf('renderNullCast returned empty for family %s', $family->value));
123    }
124    public function testRenderCastForIntegerProducesExactForm(): void
125    {
126        $renderer = new PgSqlCastRenderer();
127        $type = new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'INTEGER');
128        $result = $renderer->renderCast("'42'", $type);
129        self::assertMatchesRegularExpression('/^CAST\(\'42\'\s+AS\s+\S+\)$/i', $result, 'renderCast for INTEGER must produce CAST(expression AS type) format');
130    }
131    public function testRenderNullCastProducesExactForm(): void
132    {
133        $renderer = new PgSqlCastRenderer();
134        $type = new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'INTEGER');
135        $result = $renderer->renderNullCast($type);
136        self::assertMatchesRegularExpression('/^CAST\(NULL\s+AS\s+\S+\)$/i', $result, 'renderNullCast must produce CAST(NULL AS type) format');
137    }
138    public function testRenderCastForStringIncludesStringType(): void
139    {
140        $renderer = new PgSqlCastRenderer();
141        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'VARCHAR(255)');
142        $result = $renderer->renderCast("'hello'", $type);
143        $upper = strtoupper($result);
144        self::assertTrue(str_contains($upper, 'VARCHAR') || str_contains($upper, 'TEXT') || str_contains($upper, 'CHAR'), sprintf('renderCast for STRING must include VARCHAR, TEXT, or CHAR, got: %s', $result));
145    }
146    public function testRenderCastIsDeterministic(): void
147    {
148        $renderer = new PgSqlCastRenderer();
149        $type = new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'INTEGER');
150        self::assertSame($renderer->renderNullCast($type), $renderer->renderNullCast($type));
151    }
152    public function testRenderCastInteger(): void
153    {
154        $renderer = new PgSqlCastRenderer();
155        $type = new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'INTEGER');
156        self::assertSame("CAST('42' AS INTEGER)", $renderer->renderCast("'42'", $type));
157    }
158    public function testRenderCastBigIntPreservesWidth(): void
159    {
160        $renderer = new PgSqlCastRenderer();
161        self::assertSame('CAST(9223372036854775807 AS BIGINT)', $renderer->renderCast('9223372036854775807', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'BIGINT')));
162    }
163    public function testRenderCastPreservesArrayType(): void
164    {
165        $renderer = new PgSqlCastRenderer();
166        self::assertSame("CAST('{1,2}' AS INT4[])", $renderer->renderCast("'{1,2}'", new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'INT4[]')));
167    }
168    public function testRenderCastTrimsArrayType(): void
169    {
170        $renderer = new PgSqlCastRenderer();
171        self::assertSame("CAST('{1,2}' AS INT4[])", $renderer->renderCast("'{1,2}'", new ColumnDeclaration(ColumnTypeFamily::INTEGER, ' INT4[] ')));
172    }
173    public function testRenderCastPreservesInt2Alias(): void
174    {
175        $renderer = new PgSqlCastRenderer();
176        self::assertSame('CAST(1 AS SMALLINT)', $renderer->renderCast('1', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'int2')));
177    }
178    public function testRenderCastPreservesSmallIntAlias(): void
179    {
180        $renderer = new PgSqlCastRenderer();
181        self::assertSame('CAST(1 AS SMALLINT)', $renderer->renderCast('1', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'smallint')));
182    }
183    public function testRenderCastPreservesSmallSerialAlias(): void
184    {
185        $renderer = new PgSqlCastRenderer();
186        self::assertSame('CAST(1 AS SMALLINT)', $renderer->renderCast('1', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'smallserial')));
187    }
188    public function testRenderCastPreservesInt8Alias(): void
189    {
190        $renderer = new PgSqlCastRenderer();
191        self::assertSame('CAST(1 AS BIGINT)', $renderer->renderCast('1', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'int8')));
192    }
193    public function testRenderCastPreservesBigIntAlias(): void
194    {
195        $renderer = new PgSqlCastRenderer();
196        self::assertSame('CAST(1 AS BIGINT)', $renderer->renderCast('1', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'bigint')));
197    }
198    public function testRenderCastPreservesBigSerialAlias(): void
199    {
200        $renderer = new PgSqlCastRenderer();
201        self::assertSame('CAST(1 AS BIGINT)', $renderer->renderCast('1', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'bigserial')));
202    }
203    public function testRenderNullCastInteger(): void
204    {
205        $renderer = new PgSqlCastRenderer();
206        $type = new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'INTEGER');
207        self::assertSame('CAST(NULL AS INTEGER)', $renderer->renderNullCast($type));
208    }
209    public function testRenderNullCastString(): void
210    {
211        $renderer = new PgSqlCastRenderer();
212        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'VARCHAR(255)');
213        self::assertSame('CAST(NULL AS VARCHAR(255))', $renderer->renderNullCast($type));
214    }
215    public function testRenderNullCastText(): void
216    {
217        $renderer = new PgSqlCastRenderer();
218        $type = new ColumnDeclaration(ColumnTypeFamily::TEXT, 'TEXT');
219        self::assertSame('CAST(NULL AS TEXT)', $renderer->renderNullCast($type));
220    }
221    public function testRenderNullCastBoolean(): void
222    {
223        $renderer = new PgSqlCastRenderer();
224        $type = new ColumnDeclaration(ColumnTypeFamily::BOOLEAN, 'BOOLEAN');
225        self::assertSame('CAST(NULL AS BOOLEAN)', $renderer->renderNullCast($type));
226    }
227    public function testRenderNullCastFloat(): void
228    {
229        $renderer = new PgSqlCastRenderer();
230        $type = new ColumnDeclaration(ColumnTypeFamily::FLOAT, 'REAL');
231        self::assertSame('CAST(NULL AS REAL)', $renderer->renderNullCast($type));
232    }
233    public function testRenderNullCastDouble(): void
234    {
235        $renderer = new PgSqlCastRenderer();
236        $type = new ColumnDeclaration(ColumnTypeFamily::DOUBLE, 'DOUBLE PRECISION');
237        self::assertSame('CAST(NULL AS DOUBLE PRECISION)', $renderer->renderNullCast($type));
238    }
239    public function testRenderNullCastDecimal(): void
240    {
241        $renderer = new PgSqlCastRenderer();
242        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)');
243        self::assertSame('CAST(NULL AS NUMERIC(10,2))', $renderer->renderNullCast($type));
244    }
245    public function testRenderNullCastDate(): void
246    {
247        $renderer = new PgSqlCastRenderer();
248        $type = new ColumnDeclaration(ColumnTypeFamily::DATE, 'DATE');
249        self::assertSame('CAST(NULL AS DATE)', $renderer->renderNullCast($type));
250    }
251    public function testRenderNullCastTime(): void
252    {
253        $renderer = new PgSqlCastRenderer();
254        $type = new ColumnDeclaration(ColumnTypeFamily::TIME, 'TIME');
255        self::assertSame('CAST(NULL AS TIME)', $renderer->renderNullCast($type));
256    }
257    public function testRenderNullCastDatetime(): void
258    {
259        $renderer = new PgSqlCastRenderer();
260        $type = new ColumnDeclaration(ColumnTypeFamily::DATETIME, 'TIMESTAMP');
261        self::assertSame('CAST(NULL AS TIMESTAMP)', $renderer->renderNullCast($type));
262    }
263    public function testRenderNullCastTimestamp(): void
264    {
265        $renderer = new PgSqlCastRenderer();
266        $type = new ColumnDeclaration(ColumnTypeFamily::TIMESTAMP, 'TIMESTAMPTZ');
267        self::assertSame('CAST(NULL AS TIMESTAMP)', $renderer->renderNullCast($type));
268    }
269    public function testRenderNullCastBinary(): void
270    {
271        $renderer = new PgSqlCastRenderer();
272        $type = new ColumnDeclaration(ColumnTypeFamily::BINARY, 'BYTEA');
273        self::assertSame('CAST(NULL AS BYTEA)', $renderer->renderNullCast($type));
274    }
275    public function testRenderNullCastJson(): void
276    {
277        $renderer = new PgSqlCastRenderer();
278        $type = new ColumnDeclaration(ColumnTypeFamily::JSON, 'JSONB');
279        self::assertSame('CAST(NULL AS JSONB)', $renderer->renderNullCast($type));
280    }
281    public function testRenderNullCastUnknownUsesNativeType(): void
282    {
283        $renderer = new PgSqlCastRenderer();
284        $type = new ColumnDeclaration(ColumnTypeFamily::UNKNOWN, 'UUID');
285        self::assertSame('CAST(NULL AS UUID)', $renderer->renderNullCast($type));
286    }
287    public function testRenderNullCastUnknownEmptyNativeType(): void
288    {
289        $renderer = new PgSqlCastRenderer();
290        $type = new ColumnDeclaration(ColumnTypeFamily::UNKNOWN, '');
291        self::assertSame('CAST(NULL AS TEXT)', $renderer->renderNullCast($type));
292    }
293    public function testColumnTypeFamilyIntegerHandled(): void
294    {
295        $renderer = new PgSqlCastRenderer();
296        $type = new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'SOME_TYPE');
297        $result = $renderer->renderNullCast($type);
298        self::assertNotEmpty($result);
299        self::assertStringContainsString('CAST(', $result);
300    }
301    public function testColumnTypeFamilyFloatHandled(): void
302    {
303        $renderer = new PgSqlCastRenderer();
304        $type = new ColumnDeclaration(ColumnTypeFamily::FLOAT, 'SOME_TYPE');
305        $result = $renderer->renderNullCast($type);
306        self::assertNotEmpty($result);
307        self::assertStringContainsString('CAST(', $result);
308    }
309    public function testColumnTypeFamilyDoubleHandled(): void
310    {
311        $renderer = new PgSqlCastRenderer();
312        $type = new ColumnDeclaration(ColumnTypeFamily::DOUBLE, 'SOME_TYPE');
313        $result = $renderer->renderNullCast($type);
314        self::assertNotEmpty($result);
315        self::assertStringContainsString('CAST(', $result);
316    }
317    public function testColumnTypeFamilyDecimalHandled(): void
318    {
319        $renderer = new PgSqlCastRenderer();
320        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'SOME_TYPE');
321        $result = $renderer->renderNullCast($type);
322        self::assertNotEmpty($result);
323        self::assertStringContainsString('CAST(', $result);
324    }
325    public function testColumnTypeFamilyStringHandled(): void
326    {
327        $renderer = new PgSqlCastRenderer();
328        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'SOME_TYPE');
329        $result = $renderer->renderNullCast($type);
330        self::assertNotEmpty($result);
331        self::assertStringContainsString('CAST(', $result);
332    }
333    public function testColumnTypeFamilyTextHandled(): void
334    {
335        $renderer = new PgSqlCastRenderer();
336        $type = new ColumnDeclaration(ColumnTypeFamily::TEXT, 'SOME_TYPE');
337        $result = $renderer->renderNullCast($type);
338        self::assertNotEmpty($result);
339        self::assertStringContainsString('CAST(', $result);
340    }
341    public function testColumnTypeFamilyBooleanHandled(): void
342    {
343        $renderer = new PgSqlCastRenderer();
344        $type = new ColumnDeclaration(ColumnTypeFamily::BOOLEAN, 'SOME_TYPE');
345        $result = $renderer->renderNullCast($type);
346        self::assertNotEmpty($result);
347        self::assertStringContainsString('CAST(', $result);
348    }
349    public function testColumnTypeFamilyDateHandled(): void
350    {
351        $renderer = new PgSqlCastRenderer();
352        $type = new ColumnDeclaration(ColumnTypeFamily::DATE, 'SOME_TYPE');
353        $result = $renderer->renderNullCast($type);
354        self::assertNotEmpty($result);
355        self::assertStringContainsString('CAST(', $result);
356    }
357    public function testColumnTypeFamilyTimeHandled(): void
358    {
359        $renderer = new PgSqlCastRenderer();
360        $type = new ColumnDeclaration(ColumnTypeFamily::TIME, 'SOME_TYPE');
361        $result = $renderer->renderNullCast($type);
362        self::assertNotEmpty($result);
363        self::assertStringContainsString('CAST(', $result);
364    }
365    public function testColumnTypeFamilyDatetimeHandled(): void
366    {
367        $renderer = new PgSqlCastRenderer();
368        $type = new ColumnDeclaration(ColumnTypeFamily::DATETIME, 'SOME_TYPE');
369        $result = $renderer->renderNullCast($type);
370        self::assertNotEmpty($result);
371        self::assertStringContainsString('CAST(', $result);
372    }
373    public function testColumnTypeFamilyTimestampHandled(): void
374    {
375        $renderer = new PgSqlCastRenderer();
376        $type = new ColumnDeclaration(ColumnTypeFamily::TIMESTAMP, 'SOME_TYPE');
377        $result = $renderer->renderNullCast($type);
378        self::assertNotEmpty($result);
379        self::assertStringContainsString('CAST(', $result);
380    }
381    public function testColumnTypeFamilyBinaryHandled(): void
382    {
383        $renderer = new PgSqlCastRenderer();
384        $type = new ColumnDeclaration(ColumnTypeFamily::BINARY, 'SOME_TYPE');
385        $result = $renderer->renderNullCast($type);
386        self::assertNotEmpty($result);
387        self::assertStringContainsString('CAST(', $result);
388    }
389    public function testColumnTypeFamilyJsonHandled(): void
390    {
391        $renderer = new PgSqlCastRenderer();
392        $type = new ColumnDeclaration(ColumnTypeFamily::JSON, 'SOME_TYPE');
393        $result = $renderer->renderNullCast($type);
394        self::assertNotEmpty($result);
395        self::assertStringContainsString('CAST(', $result);
396    }
397    public function testColumnTypeFamilyUnknownHandled(): void
398    {
399        $renderer = new PgSqlCastRenderer();
400        $type = new ColumnDeclaration(ColumnTypeFamily::UNKNOWN, 'SOME_TYPE');
401        $result = $renderer->renderNullCast($type);
402        self::assertNotEmpty($result);
403        self::assertStringContainsString('CAST(', $result);
404    }
405    public function testRenderCastDecimalWithPrecisionAndScale(): void
406    {
407        $renderer = new PgSqlCastRenderer();
408        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'NUMERIC(10,2)');
409        self::assertSame("CAST('42.5' AS NUMERIC(10,2))", $renderer->renderCast("'42.5'", $type));
410    }
411    public function testRenderCastDecimalWithPrecisionOnly(): void
412    {
413        $renderer = new PgSqlCastRenderer();
414        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'NUMERIC(8)');
415        self::assertSame("CAST('100' AS NUMERIC(8,0))", $renderer->renderCast("'100'", $type));
416    }
417    public function testRenderCastDecimalBare(): void
418    {
419        $renderer = new PgSqlCastRenderer();
420        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'NUMERIC');
421        self::assertSame("CAST('99' AS NUMERIC)", $renderer->renderCast("'99'", $type));
422    }
423    public function testRenderCastDecimalLowercaseNativeType(): void
424    {
425        $renderer = new PgSqlCastRenderer();
426        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'numeric(10,2)');
427        self::assertSame("CAST('42.5' AS NUMERIC(10,2))", $renderer->renderCast("'42.5'", $type));
428    }
429    public function testRenderCastDecimalFromDecimalKeyword(): void
430    {
431        $renderer = new PgSqlCastRenderer();
432        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'DECIMAL(12,4)');
433        self::assertSame("CAST('3.14' AS NUMERIC(12,4))", $renderer->renderCast("'3.14'", $type));
434    }
435    public function testRenderCastStringWithVarcharLength(): void
436    {
437        $renderer = new PgSqlCastRenderer();
438        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'VARCHAR(100)');
439        self::assertSame("CAST('hi' AS VARCHAR(100))", $renderer->renderCast("'hi'", $type));
440    }
441    public function testRenderCastStringLowercaseVarchar(): void
442    {
443        $renderer = new PgSqlCastRenderer();
444        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'varchar(50)');
445        self::assertSame("CAST('hi' AS VARCHAR(50))", $renderer->renderCast("'hi'", $type));
446    }
447    public function testRenderCastStringWithoutLength(): void
448    {
449        $renderer = new PgSqlCastRenderer();
450        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'VARCHAR');
451        self::assertSame("CAST('hi' AS VARCHAR)", $renderer->renderCast("'hi'", $type));
452    }
453    public function testRenderCastCharacterVaryingWithoutLength(): void
454    {
455        $renderer = new PgSqlCastRenderer();
456        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'CHARACTER VARYING');
457        self::assertSame("CAST('hi' AS VARCHAR)", $renderer->renderCast("'hi'", $type));
458    }
459    public function testRenderCastUnknownStringNativeTypeFallsBackToText(): void
460    {
461        $renderer = new PgSqlCastRenderer();
462        $type = new ColumnDeclaration(ColumnTypeFamily::STRING, 'CUSTOM_STRING');
463        self::assertSame("CAST('hi' AS TEXT)", $renderer->renderCast("'hi'", $type));
464    }
465    public function testRenderCastDecimalLowercaseDecimalKeyword(): void
466    {
467        $renderer = new PgSqlCastRenderer();
468        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'decimal(5,2)');
469        self::assertSame("CAST('1.0' AS NUMERIC(5,2))", $renderer->renderCast("'1.0'", $type));
470    }
471    public function testRenderCastDecimalPrecisionOnlyLowercase(): void
472    {
473        $renderer = new PgSqlCastRenderer();
474        $type = new ColumnDeclaration(ColumnTypeFamily::DECIMAL, 'decimal(6)');
475        self::assertSame("CAST('1' AS NUMERIC(6,0))", $renderer->renderCast("'1'", $type));
476    }
477}
478