Passed
Pull Request — dev (#90)
by Wilmer
03:57
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\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...
18
use Yiisoft\Db\Query\QueryInterface;
19
20
final class DMLQueryBuilder extends AbstractDMLQueryBuilder
21
{
22 324
    public function __construct(private QueryBuilderInterface $queryBuilder)
23
    {
24 324
        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(
58
        string $table,
59
        QueryInterface|array $insertColumns,
60
        bool|array $updateColumns,
61
        array &$params
62
    ): string {
63
        /** @var Constraint[] $constraints */
64 18
        $constraints = [];
65
66
        /**
67
         * @psalm-var string[] $insertNames
68
         * @psalm-var string[] $updateNames
69
         * @psalm-var array<string, ExpressionInterface|string>|bool $updateColumns
70
         */
71 18
        [$uniqueNames, $insertNames, $updateNames] = $this->queryBuilder->prepareUpsertColumns(
72
            $table,
73
            $insertColumns,
74
            $updateColumns,
75
            $constraints
76
        );
77
78 18
        if (empty($uniqueNames)) {
79 3
            return $this->insert($table, $insertColumns, $params);
80
        }
81
82
        /**
83
         * @psalm-var string[] $placeholders
84
         */
85 15
        [, $placeholders, $values, $params] = $this->queryBuilder->prepareInsertValues($table, $insertColumns, $params);
86
87 15
        $insertSql = 'INSERT OR IGNORE INTO '
88 15
            . $this->queryBuilder->quoter()->quoteTableName($table)
89 15
            . (!empty($insertNames) ? ' (' . implode(', ', $insertNames) . ')' : '')
90 15
            . (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : "$values");
91
92 15
        if ($updateColumns === false) {
0 ignored issues
show
introduced by
The condition $updateColumns === false is always false.
Loading history...
93 5
            return $insertSql;
94
        }
95
96 10
        $updateCondition = ['or'];
97 10
        $quotedTableName = $this->queryBuilder->quoter()->quoteTableName($table);
98
99 10
        foreach ($constraints as $constraint) {
100 10
            $constraintCondition = ['and'];
101
            /** @psalm-var string[] */
102 10
            $columnsNames = $constraint->getColumnNames();
103 10
            foreach ($columnsNames as $name) {
104 10
                $quotedName = $this->queryBuilder->quoter()->quoteColumnName($name);
105 10
                $constraintCondition[] = "$quotedTableName.$quotedName=(SELECT $quotedName FROM `EXCLUDED`)";
106
            }
107 10
            $updateCondition[] = $constraintCondition;
108
        }
109
110 10
        if ($updateColumns === true) {
0 ignored issues
show
introduced by
The condition $updateColumns === true is always false.
Loading history...
111 4
            $updateColumns = [];
112 4
            foreach ($updateNames as $name) {
113 4
                $quotedName = $this->queryBuilder->quoter()->quoteColumnName($name);
114
115 4
                if (strrpos($quotedName, '.') === false) {
116 4
                    $quotedName = "(SELECT $quotedName FROM `EXCLUDED`)";
117
                }
118 4
                $updateColumns[$name] = new Expression($quotedName);
119
            }
120
        }
121
122
        /** @var array $params */
123 10
        $updateSql = 'WITH "EXCLUDED" ('
124 10
            . implode(', ', $insertNames)
125 10
            . ') AS (' . (!empty($placeholders)
126 4
                ? 'VALUES (' . implode(', ', $placeholders) . ')'
127 10
                : ltrim("$values", ' ')) . ') ' .
128 10
                $this->update($table, $updateColumns, $updateCondition, $params);
129
130 10
        return "$updateSql; $insertSql;";
131
    }
132
}
133