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