Lines 100.00% 11 / 11
Functions and Methods 100.00% 10 / 10
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
PostgresConnection 100.00% 11 / 11 100.00% 10 / 10 10 100.00% 1 / 1
 getDefaultQueryGrammar 100.00% 1 / 1 100.00% 1 / 1 1
 getDefaultSchemaGrammar 100.00% 1 / 1 100.00% 1 / 1 1
 getDefaultSchemaInspector 100.00% 1 / 1 100.00% 1 / 1 1
 getDefaultValueCodec 100.00% 1 / 1 100.00% 1 / 1 1
 supportsSavepoints 100.00% 1 / 1 100.00% 1 / 1 1
 supportsTransactionalDdl 100.00% 1 / 1 100.00% 1 / 1 1
 createSavepoint 100.00% 1 / 1 100.00% 1 / 1 1
 releaseSavepoint 100.00% 1 / 1 100.00% 1 / 1 1
 rollbackToSavepoint 100.00% 1 / 1 100.00% 1 / 1 1
 withLock 100.00% 2 / 2 100.00% 1 / 1 1
1<?php
2
3declare(strict_types=1);
4
5namespace BlueprintAU\Radiant\Database\Connections;
6
7use BlueprintAU\Radiant\Database\Grammars\Grammar;
8use BlueprintAU\Radiant\Database\Grammars\PostgresGrammar;
9use BlueprintAU\Radiant\Database\Schema\Grammars\PostgresSchemaGrammar;
10use BlueprintAU\Radiant\Database\Schema\Grammars\SchemaGrammar;
11use BlueprintAU\Radiant\Database\Schema\Inspectors\PostgresSchemaInspector;
12use BlueprintAU\Radiant\Database\Schema\Inspectors\SchemaInspector;
13use BlueprintAU\Radiant\Database\ValueCodecs\PostgresValueCodec;
14use BlueprintAU\Radiant\Database\ValueCodecs\ValueCodecInterface;
15use Override;
16
17/**
18 * A database connection backed by Postgres.
19 *
20 * Postgres supports savepoints for nested transactions, so all four
21 * transaction hooks map onto `SAVEPOINT`, `RELEASE SAVEPOINT` and
22 * `ROLLBACK TO SAVEPOINT`. It also overrides the default value codec with
23 * {@see PostgresValueCodec} so datetimes are formatted with microsecond
24 * precision, matching Postgres' native `timestamp` type.
25 *
26 * @see SqlConnection
27 *
28 * @extends SqlConnection<\BlueprintAU\Radiant\Database\Grammars\PostgresGrammar, \BlueprintAU\Radiant\Database\Schema\Grammars\PostgresSchemaGrammar, \BlueprintAU\Radiant\Database\Schema\Inspectors\PostgresSchemaInspector>
29 */
30final class PostgresConnection extends SqlConnection
31{
32    /**
33     * The default query grammar for this connection.
34     *
35     * @return Grammar
36     */
37    protected function getDefaultQueryGrammar(): Grammar
38    {
39        return new PostgresGrammar();
40    }
41
42    /**
43     * The default schema grammar for this connection.
44     *
45     * @return SchemaGrammar
46     */
47    protected function getDefaultSchemaGrammar(): SchemaGrammar
48    {
49        return new PostgresSchemaGrammar();
50    }
51
52    /**
53     * The dialect's live-schema reader.
54     *
55     * @return PostgresSchemaInspector
56     */
57    protected function getDefaultSchemaInspector(): SchemaInspector
58    {
59        return new PostgresSchemaInspector($this->pdo);
60    }
61
62    /**
63     * The default value codec for this connection.
64     *
65     * Postgres' native `timestamp` stores microseconds, so datetimes are
66     * formatted as `Y-m-d H:i:s.u` on the write path.
67     *
68     * @return ValueCodecInterface
69     */
70    protected function getDefaultValueCodec(): ValueCodecInterface
71    {
72        return new PostgresValueCodec();
73    }
74
75    /**
76     * Whether this dialect supports savepoints for nested transactions.
77     *
78     * @return bool
79     */
80    protected function supportsSavepoints(): bool
81    {
82        return true;
83    }
84
85    /**
86     * Postgres DDL is transactional — schema statements roll back with
87     * the transaction.
88     *
89     * @return bool
90     */
91    #[Override]
92    public function supportsTransactionalDdl(): bool
93    {
94        return true;
95    }
96
97    /**
98     * Create a named savepoint.
99     *
100     * @param  string  $name
101     */
102    protected function createSavepoint(string $name): void
103    {
104        $this->pdo->exec("SAVEPOINT {$name}");
105    }
106
107    /**
108     * Release a named savepoint.
109     *
110     * @param  string  $name
111     */
112    protected function releaseSavepoint(string $name): void
113    {
114        $this->pdo->exec("RELEASE SAVEPOINT {$name}");
115    }
116
117    /**
118     * Roll back to a named savepoint.
119     *
120     * @param  string  $name
121     */
122    protected function rollbackToSavepoint(string $name): void
123    {
124        $this->pdo->exec("ROLLBACK TO SAVEPOINT {$name}");
125    }
126
127    /**
128     * Run the callback under a Postgres session advisory lock on the given
129     * lock domain.
130     *
131     * @template TReturn
132     *
133     * @param  callable(): TReturn  $callback
134     * @param  string  $name
135     * @return TReturn
136     * @throws \Throwable
137     */
138    #[Override]
139    public function withLock(callable $callback, string $name): mixed
140    {
141        return (new \BlueprintAU\Radiant\Database\Locks\PostgresLock($this))
142            ->withLock($callback, $name);
143    }
144}