Passed
Branch dev (ea35c5)
by Wilmer
17:29 queued 12:43
created

DMLQueryBuilder::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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