packages/ztd-query-postgres/src/Rewrite/Sampling/PgSqlTableSampleRewriter.php
1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Postgres\Rewrite\Sampling;
6
7use ZtdQuery\Exception\UnsupportedSqlException;
8use ZtdQuery\Platform\Postgres\Sql\PgSqlIdentifierQuoter;
9use ZtdQuery\Platform\Postgres\Sql\Sampling\PgSqlTableSample;
10use ZtdQuery\Platform\Postgres\Sql\Sampling\PgSqlTableSampleParser;
11
12/**
13 * Table sample rewriter for PostgreSQL queries.
14 */
15final class PgSqlTableSampleRewriter
16{
17 private PgSqlTableSampleParser $parser;
18 private PgSqlIdentifierQuoter $quoter;
19
20 /**
21 * Initializes the collaborators and state used by this table sample rewriter.
22 */
23 public function __construct()
24 {
25 $this->parser = new PgSqlTableSampleParser();
26 $this->quoter = new PgSqlIdentifierQuoter();
27 }
28
29 /**
30 * @param array<string, array<string, mixed>> $tables
31 * @throws UnsupportedSqlException
32 */
33 public function rewrite(string $sql, array $tables): string
34 {
35 $samples = $this->parser->parse($sql);
36 usort($samples, static fn (PgSqlTableSample $left, PgSqlTableSample $right): int => $right->startOffset <=> $left->startOffset);
37
38 foreach ($samples as $index => $sample) {
39 $columns = (new TableColumns())->columns($sample->tableName, $tables);
40 if ($columns === []) {
41 throw new UnsupportedSqlException(
42 $sql,
43 "Cannot determine columns for TABLESAMPLE source '{$sample->tableName}'",
44 );
45 }
46 $replacement = (new SampleProjection($this->quoter))->replacement($sample, $columns, $index);
47 $sql = substr_replace(
48 $sql,
49 $replacement,
50 $sample->startOffset,
51 $sample->endOffset - $sample->startOffset,
52 );
53 }
54
55 return $sql;
56 }
57}
58