Passed
Pull Request — 2.x (#231)
by
unknown
17:00
created

PostgresUpsertQuery::withDriver()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of Cycle ORM package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database\Driver\Postgres\Query;
13
14
use Cycle\Database\Driver\DriverInterface;
15
use Cycle\Database\Driver\Postgres\PostgresDriver;
16
use Cycle\Database\Exception\BuilderException;
17
use Cycle\Database\Exception\ReadonlyConnectionException;
18
use Cycle\Database\Injection\FragmentInterface;
19
use Cycle\Database\Query\ReturningInterface;
20
use Cycle\Database\Query\QueryInterface;
21
use Cycle\Database\Query\QueryParameters;
22
use Cycle\Database\Query\UpsertQuery;
23
use Cycle\Database\StatementInterface;
24
25
/**
26
 * Postgres driver requires a slightly different way to handle last insert id.
27
 */
28
class PostgresUpsertQuery extends UpsertQuery implements ReturningInterface
29
{
30
    /** @var PostgresDriver|null */
31
    protected ?DriverInterface $driver = null;
32
33
    /** @deprecated */
34
    protected string|FragmentInterface|null $returning = null;
35
36
    /** @var list<FragmentInterface|non-empty-string> */
0 ignored issues
show
Bug introduced by
The type Cycle\Database\Driver\Postgres\Query\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
37
    protected array $returningColumns = [];
38
39
    public function withDriver(DriverInterface $driver, ?string $prefix = null): QueryInterface
40
    {
41
        $driver instanceof PostgresDriver or throw new BuilderException(
42
            'Postgres UpsertQuery can be used only with Postgres driver',
43
        );
44
45
        return parent::withDriver($driver, $prefix);
46
    }
47
48
    /**
49
     * Set returning column. If not set, the driver will detect PK automatically.
50
     */
51
    public function returning(string|FragmentInterface ...$columns): self
52
    {
53
        $columns === [] and throw new BuilderException('RETURNING clause should contain at least 1 column.');
54
55
        $this->returning = \count($columns) === 1 ? \reset($columns) : null;
0 ignored issues
show
Deprecated Code introduced by
The property Cycle\Database\Driver\Po...UpsertQuery::$returning has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

55
        /** @scrutinizer ignore-deprecated */ $this->returning = \count($columns) === 1 ? \reset($columns) : null;
Loading history...
56
57
        $this->returningColumns = \array_values($columns);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_values($columns) of type array is incompatible with the declared type Cycle\Database\Driver\Postgres\Query\list of property $returningColumns.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
58
59
        return $this;
60
    }
61
62
    public function run(): mixed
63
    {
64
        $params = new QueryParameters();
65
        $queryString = $this->sqlStatement($params);
66
67
        $this->driver->isReadonly() and throw ReadonlyConnectionException::onWriteStatementExecution();
0 ignored issues
show
Bug introduced by
The method isReadonly() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

67
        $this->driver->/** @scrutinizer ignore-call */ 
68
                       isReadonly() and throw ReadonlyConnectionException::onWriteStatementExecution();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
68
69
        $result = $this->driver->query($queryString, $params->getParameters());
70
71
        try {
72
            if ($this->returningColumns !== []) {
73
                if (\count($this->returningColumns) === 1) {
74
                    return $result->fetchColumn();
75
                }
76
77
                return $result->fetch(StatementInterface::FETCH_ASSOC);
78
            }
79
80
            // Return PK if no RETURNING clause is set
81
            if ($this->getPrimaryKey() !== null) {
82
                return $result->fetchColumn();
83
            }
84
85
            return null;
86
        } finally {
87
            $result->close();
88
        }
89
    }
90
91
    public function getTokens(): array
92
    {
93
        return parent::getTokens() + [
94
            'return'  => $this->returningColumns !== [] ? $this->returningColumns : (array) $this->getPrimaryKey(),
95
        ];
96
    }
97
98
    private function getPrimaryKey(): ?string
99
    {
100
        try {
101
            return $this->driver?->getPrimaryKey($this->prefix, $this->table);
0 ignored issues
show
Bug introduced by
The method getPrimaryKey() does not exist on Cycle\Database\Driver\DriverInterface. It seems like you code against a sub-type of Cycle\Database\Driver\DriverInterface such as Cycle\Database\Driver\Driver. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
            return $this->driver?->/** @scrutinizer ignore-call */ getPrimaryKey($this->prefix, $this->table);
Loading history...
102
        } catch (\Throwable) {
103
            return null;
104
        }
105
    }
106
}
107