Test Failed
Pull Request — master (#82)
by Wilmer
24:21 queued 13:10
created

DMLQueryBuilder::resetSequence()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
dl 0
loc 22
rs 9.5222
c 1
b 0
f 0
cc 5
nc 4
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Sqlite;
6
7
use Generator;
8
use InvalidArgumentException;
9
use Throwable;
10
use Yiisoft\Db\Constraint\Constraint;
11
use Yiisoft\Db\Exception\Exception;
12
use Yiisoft\Db\Expression\Expression;
13
use Yiisoft\Db\Expression\ExpressionInterface;
14
use Yiisoft\Db\Query\DMLQueryBuilder as AbstractDMLQueryBuilder;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Query\DMLQueryBuilder 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...
15
use Yiisoft\Db\Query\Query;
16
use Yiisoft\Db\Query\QueryBuilderInterface;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\Query\QueryBuilderInterface 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...
17
18
final class DMLQueryBuilder extends AbstractDMLQueryBuilder
19
{
20
    public function __construct(private QueryBuilderInterface $queryBuilder)
21
    {
22
        parent::__construct($queryBuilder);
23
    }
24
25
    public function resetSequence(string $tableName, mixed $value = null): string
26
    {
27
        $table = $this->queryBuilder->schema()->getTableSchema($tableName);
28
29
        if ($table !== null && $table->getSequenceName() !== null) {
30
            $tableName = $this->queryBuilder->quoter()->quoteTableName($tableName);
31
            if ($value === null) {
32
                $pk = $table->getPrimaryKey();
33
                $key = $this->queryBuilder->quoter()->quoteColumnName(reset($pk));
34
                $value = $this->queryBuilder->command()->setSql("SELECT MAX($key) FROM $tableName")->queryScalar();
35
            } else {
36
                $value = (int) $value - 1;
37
            }
38
39
            return "UPDATE sqlite_sequence SET seq='$value' WHERE name='{$table->getName()}'";
40
        }
41
42
        if ($table === null) {
43
            throw new InvalidArgumentException("Table not found: $tableName");
44
        }
45
46
        throw new InvalidArgumentException("There is not sequence associated with table '$tableName'.'");
47
    }
48
49
    public function upsert(string $table, Query|array $insertColumns, bool|array $updateColumns, array &$params): string
50
    {
51
        /** @var Constraint[] $constraints */
52
        $constraints = [];
53
54
        /**
55
         * @psalm-var array<array-key, string> $insertNames
56
         * @psalm-var array<array-key, string> $updateNames
57
         * @psalm-var array<string, ExpressionInterface|string>|bool $updateColumns
58
         */
59
        [$uniqueNames, $insertNames, $updateNames] = $this->queryBuilder->prepareUpsertColumns(
60
            $table,
61
            $insertColumns,
62
            $updateColumns,
63
            $constraints
64
        );
65
66
        if (empty($uniqueNames)) {
67
            return $this->insert($table, $insertColumns, $params);
68
        }
69
70
        /**
71
         * @psalm-var array<array-key, string> $placeholders
72
         */
73
        [, $placeholders, $values, $params] = $this->queryBuilder->prepareInsertValues($table, $insertColumns, $params);
74
75
        $insertSql = 'INSERT OR IGNORE INTO '
76
            . $this->queryBuilder->quoter()->quoteTableName($table)
77
            . (!empty($insertNames) ? ' (' . implode(', ', $insertNames) . ')' : '')
78
            . (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : "$values");
79
80
        if ($updateColumns === false) {
0 ignored issues
show
introduced by
The condition $updateColumns === false is always false.
Loading history...
81
            return $insertSql;
82
        }
83
84
        $updateCondition = ['or'];
85
        $quotedTableName = $this->queryBuilder->quoter()->quoteTableName($table);
86
87
        foreach ($constraints as $constraint) {
88
            $constraintCondition = ['and'];
89
            /** @psalm-var array<array-key, string> */
90
            $columnsNames = $constraint->getColumnNames();
91
            foreach ($columnsNames as $name) {
92
                $quotedName = $this->queryBuilder->quoter()->quoteColumnName($name);
93
                $constraintCondition[] = "$quotedTableName.$quotedName=(SELECT $quotedName FROM `EXCLUDED`)";
94
            }
95
            $updateCondition[] = $constraintCondition;
96
        }
97
98
        if ($updateColumns === true) {
0 ignored issues
show
introduced by
The condition $updateColumns === true is always false.
Loading history...
99
            $updateColumns = [];
100
            foreach ($updateNames as $name) {
101
                $quotedName = $this->queryBuilder->quoter()->quoteColumnName($name);
102
103
                if (strrpos($quotedName, '.') === false) {
104
                    $quotedName = "(SELECT $quotedName FROM `EXCLUDED`)";
105
                }
106
                $updateColumns[$name] = new Expression($quotedName);
107
            }
108
        }
109
110
        $updateSql = 'WITH "EXCLUDED" ('
111
            . implode(', ', $insertNames)
112
            . ') AS (' . (!empty($placeholders)
113
                ? 'VALUES (' . implode(', ', $placeholders) . ')'
114
                : ltrim("$values", ' ')) . ') ' . $this->update($table, $updateColumns, $updateCondition, $params);
115
116
        return "$updateSql; $insertSql;";
117
    }
118
}
119