Completed
Branch feature/pre-split (ca29cf)
by Anton
03:23
created

PostgresDriver::insertBuilder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 7
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 7
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Database\Drivers\Postgres;
10
11
use Psr\Log\LoggerInterface;
12
use Spiral\Core\FactoryInterface;
13
use Spiral\Core\MemoryInterface;
14
use Spiral\Database\Builders\InsertQuery;
15
use Spiral\Database\DatabaseInterface;
16
use Spiral\Database\Drivers\Postgres\Schemas\PostgresTable;
17
use Spiral\Database\Entities\AbstractHandler;
18
use Spiral\Database\Entities\Driver;
19
use Spiral\Database\Exceptions\DriverException;
20
21
/**
22
 * Talks to postgres databases.
23
 */
24
class PostgresDriver extends Driver
25
{
26
    /**
27
     * Driver type.
28
     */
29
    const TYPE = DatabaseInterface::POSTGRES;
30
31
    /**
32
     * Driver schemas.
33
     */
34
    const TABLE_SCHEMA_CLASS = PostgresTable::class;
35
36
    /**
37
     * Query compiler class.
38
     */
39
    const QUERY_COMPILER = PostgresCompiler::class;
40
41
    /**
42
     * Cached list of primary keys associated with their table names. Used by InsertBuilder to
43
     * emulate last insert id.
44
     *
45
     * @var array
46
     */
47
    private $primaryKeys = [];
48
49
    /**
50
     * Used to store information about associated primary keys.
51
     *
52
     * @var MemoryInterface
53
     */
54
    protected $memory = null;
55
56
    /**
57
     * @param string           $name
58
     * @param array            $options
59
     * @param FactoryInterface $factory
60
     * @param MemoryInterface  $memory Optional.
61
     */
62
    public function __construct(
63
        $name,
64
        array $options,
65
        FactoryInterface $factory,
66
        MemoryInterface $memory = null
67
    ) {
68
        parent::__construct($name, $options, $factory);
69
        $this->memory = $memory;
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    public function hasTable(string $name): bool
76
    {
77
        $query = "SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' AND table_name = ?";
78
79
        return (bool)$this->query($query, [$name])->fetchColumn();
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function truncateData(string $table)
86
    {
87
        $this->statement("TRUNCATE TABLE {$this->identifier($table)}");
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93
    public function tableNames(): array
94
    {
95
        $query = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE'";
96
97
        $tables = [];
98
        foreach ($this->query($query) as $row) {
99
            $tables[] = $row['table_name'];
100
        }
101
102
        return $tables;
103
    }
104
105
    /**
106
     * Get singular primary key associated with desired table. Used to emulate last insert id.
107
     *
108
     * @param string $prefix Database prefix if any.
109
     * @param string $table  Fully specified table name, including postfix.
110
     *
111
     * @return string|null
112
     *
113
     * @throws DriverException
114
     */
115
    public function getPrimary(string $prefix, string $table): string
116
    {
117
        if (!empty($this->memory) && empty($this->primaryKeys)) {
118
            $this->primaryKeys = (array)$this->memory->loadData($this->getSource() . '.keys');
119
        }
120
121
        if (!empty($this->primaryKeys) && array_key_exists($table, $this->primaryKeys)) {
122
            return $this->primaryKeys[$table];
123
        }
124
125
        if (!$this->hasTable($prefix . $table)) {
126
            throw new DriverException(
127
                "Unable to fetch table primary key, no such table '{$prefix}{$table}' exists"
128
            );
129
        }
130
131
        $this->primaryKeys[$table] = $this->tableSchema($table, $prefix)->getPrimaryKeys();
132
        if (count($this->primaryKeys[$table]) === 1) {
133
            //We do support only single primary key
134
            $this->primaryKeys[$table] = $this->primaryKeys[$table][0];
135
        } else {
136
            $this->primaryKeys[$table] = null;
137
        }
138
139
        //Caching
140
        if (!empty($this->memory)) {
141
            $this->memory->saveData($this->getSource() . ',keys', $this->primaryKeys);
142
        }
143
144
        return $this->primaryKeys[$table];
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     *
150
     * Postgres uses custom insert query builder in order to return value of inserted row.
151
     */
152 View Code Duplication
    public function insertBuilder(string $prefix, array $parameters = []): InsertQuery
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
153
    {
154
        return $this->factory->make(
155
            PostgresQuery::class,
156
            ['driver' => $this, 'compiler' => $this->queryCompiler($prefix),] + $parameters
157
        );
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163
    protected function createPDO(): \PDO
164
    {
165
        //Spiral is purely UTF-8
166
        $pdo = parent::createPDO();
167
        $pdo->exec("SET NAMES 'UTF-8'");
168
169
        return $pdo;
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function getHandler(LoggerInterface $logger = null): AbstractHandler
176
    {
177
        return new PostgresHandler($this, $logger);
178
    }
179
}
180