Passed
Push — master ( 3bf289...079122 )
by Wilmer
11:20 queued 07:17
created

src/DMLQueryBuilder.php (2 issues)

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