packages/ztd-query-postgres/src/Schema/Reflection/Catalog/PartitionKeys.php

1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Postgres\Schema\Reflection\Catalog;
6
7use ZtdQuery\Connection\ConnectionInterface;
8use ZtdQuery\Platform\Postgres\Sql\Partition\PgSqlPartitionParser;
9use ZtdQuery\Schema\Partition\TablePartitionKey;
10
11/**
12 * Reflects the partition-key expression attached to each partitioned table.
13 *
14 * @visibility root
15 */
16final class PartitionKeys
17{
18    /**
19     * Supplies access to the current PostgreSQL schema.
20     */
21    public function __construct(private readonly ConnectionInterface $connection)
22    {
23    }
24
25    /**
26     * Parses catalog partition-key declarations into typed metadata.
27     * @return array<string, TablePartitionKey>
28     */
29    public function reflect(): array
30    {
31        $parser = new PgSqlPartitionParser();
32        $keys = [];
33        $keyStatement = $this->connection->query(
34            'SELECT c.relname AS table_name, pg_get_partkeydef(c.oid) AS partition_key '
35            . 'FROM pg_partitioned_table pt '
36            . 'JOIN pg_class c ON c.oid = pt.partrelid '
37            . 'JOIN pg_namespace n ON n.oid = c.relnamespace '
38            . 'WHERE n.nspname = current_schema() ORDER BY c.relname',
39        );
40        if ($keyStatement !== false) {
41            foreach ($keyStatement->fetchAll() as $row) {
42                $tableName = $row['table_name'] ?? null;
43                $partitionKey = $row['partition_key'] ?? null;
44                if (!is_string($tableName) || $tableName === '' || !is_string($partitionKey)) {
45                    continue;
46                }
47                $key = $parser->parseKey("PARTITION BY $partitionKey");
48                if ($key !== null) {
49                    $keys[$tableName] = $key;
50                }
51            }
52        }
53
54        return $keys;
55    }
56}
57