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