packages/sql-fixture/src/Platform/PostgreSql/Schema/CatalogColumn.php
1<?php
2
3declare(strict_types=1);
4
5namespace SqlFixture\Platform\PostgreSql\Schema;
6
7/**
8 * Interprets PostgreSQL catalog type and default metadata.
9 *
10 * @visibility root
11 */
12final class CatalogColumn
13{
14 /**
15 * @param array{data_type: string, character_maximum_length: ?string, numeric_precision: ?string, numeric_scale: ?string, udt_name: string} $col
16 */
17 public function mapDataType(array $col): string
18 {
19 $type = strtoupper($col['data_type']);
20
21 if ($type === 'CHARACTER VARYING' && $col['character_maximum_length'] !== null) {
22 return 'VARCHAR(' . $col['character_maximum_length'] . ')';
23 }
24
25 if ($type === 'CHARACTER' && $col['character_maximum_length'] !== null) {
26 return 'CHAR(' . $col['character_maximum_length'] . ')';
27 }
28
29 if ($type === 'NUMERIC' && $col['numeric_precision'] !== null) {
30 $precision = $col['numeric_precision'];
31 if ($col['numeric_scale'] !== null && $col['numeric_scale'] !== '0') {
32 return "NUMERIC({$precision}, {$col['numeric_scale']})";
33 }
34 return "NUMERIC({$precision})";
35 }
36
37 if ($type === 'ARRAY') {
38 return strtoupper($col['udt_name']);
39 }
40
41 if ($type === 'USER-DEFINED') {
42 return strtoupper($col['udt_name']);
43 }
44
45 return $type;
46 }
47
48 /**
49 * @param array{data_type: string, udt_name: string, character_maximum_length: ?string, numeric_precision: ?string, numeric_scale: ?string} $row
50 */
51 public function resolveType(array $row): string
52 {
53 $type = strtoupper($row['data_type']);
54
55 if ($type === 'ARRAY') {
56 $elementType = strtoupper(ltrim($row['udt_name'], '_'));
57 return $elementType . '_ARRAY';
58 }
59
60 if ($type === 'USER-DEFINED') {
61 return strtoupper($row['udt_name']);
62 }
63
64 return $type;
65 }
66
67 /**
68 * Parses default.
69 */
70 public function parseDefault(?string $value): int|float|bool|string|null
71 {
72 if ($value === null) {
73 return null;
74 }
75
76 if (strtoupper($value) === 'NULL' || strtoupper($value) === 'NULL::') {
77 return null;
78 }
79
80 if (str_contains($value, 'nextval(')) {
81 return null;
82 }
83
84 if (preg_match("/^'(.*)'::.*$/s", $value, $matches) === 1) {
85 return $matches[1];
86 }
87
88 if (preg_match("/^'(.*)'$/s", $value, $matches) === 1) {
89 return $matches[1];
90 }
91
92 if (strtolower($value) === 'true') {
93 return true;
94 }
95 if (strtolower($value) === 'false') {
96 return false;
97 }
98
99 if (is_numeric($value)) {
100 if (str_contains($value, '.')) {
101 return (float) $value;
102 }
103 return (int) $value;
104 }
105
106 return $value;
107 }
108}
109